diff --git a/Gopkg.lock b/Gopkg.lock index 09eb1592..2357e880 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -53,8 +53,8 @@ [[projects]] branch = "master" name = "golang.org/x/crypto" - packages = ["curve25519","ed25519","ed25519/internal/edwards25519","internal/chacha20","poly1305","ssh","ssh/testdata"] - revision = "a3947c90260b2290d5db1b779520e75f21ad8baf" + packages = ["curve25519","ed25519","ed25519/internal/edwards25519","internal/chacha20","internal/subtle","poly1305","ssh","ssh/knownhosts","ssh/testdata"] + revision = "cdb2816747ef231992582a5f410b771944415b2a" source = "https://github.com/tg123/sshpiper.crypto" [[projects]] @@ -66,6 +66,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "9e42cf42e27d0d44f175e90958f545127d53a6ba490856c10094dffdb54e79f1" + inputs-digest = "4a95a16e8ce17e8bafabc938449a48b33d8ad760eeeee16128240972b4706032" solver-name = "gps-cdcl" solver-version = 1 diff --git a/vendor/golang.org/x/crypto/CONTRIBUTING.md b/vendor/golang.org/x/crypto/CONTRIBUTING.md index 88dff59b..d0485e88 100644 --- a/vendor/golang.org/x/crypto/CONTRIBUTING.md +++ b/vendor/golang.org/x/crypto/CONTRIBUTING.md @@ -4,16 +4,15 @@ Go is an open source project. It is the work of hundreds of contributors. We appreciate your help! - ## Filing issues When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: -1. What version of Go are you using (`go version`)? -2. What operating system and processor architecture are you using? -3. What did you do? -4. What did you expect to see? -5. What did you see instead? +1. What version of Go are you using (`go version`)? +2. What operating system and processor architecture are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. The gophers there will answer or ask you to file an issue if you've tripped over a bug. @@ -23,9 +22,5 @@ The gophers there will answer or ask you to file an issue if you've tripped over Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) before sending patches. -**We do not accept GitHub pull requests** -(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review). - Unless otherwise noted, the Go source files are distributed under the BSD-style license found in the LICENSE file. - diff --git a/vendor/golang.org/x/crypto/acme/acme.go b/vendor/golang.org/x/crypto/acme/acme.go index fa9c4b39..c6fd9989 100644 --- a/vendor/golang.org/x/crypto/acme/acme.go +++ b/vendor/golang.org/x/crypto/acme/acme.go @@ -14,7 +14,6 @@ package acme import ( - "bytes" "context" "crypto" "crypto/ecdsa" @@ -23,6 +22,8 @@ import ( "crypto/sha256" "crypto/tls" "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" "encoding/base64" "encoding/hex" "encoding/json" @@ -33,14 +34,26 @@ import ( "io/ioutil" "math/big" "net/http" - "strconv" "strings" "sync" "time" ) -// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA. -const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" +const ( + // LetsEncryptURL is the Directory endpoint of Let's Encrypt CA. + LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory" + + // ALPNProto is the ALPN protocol name used by a CA server when validating + // tls-alpn-01 challenges. + // + // Package users must ensure their servers can negotiate the ACME ALPN in + // order for tls-alpn-01 challenge verifications to succeed. + // See the crypto/tls package's Config.NextProtos field. + ALPNProto = "acme-tls/1" +) + +// idPeACMEIdentifierV1 is the OID for the ACME extension for the TLS-ALPN challenge. +var idPeACMEIdentifierV1 = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 30, 1} const ( maxChainLen = 5 // max depth and breadth of a certificate chain @@ -64,6 +77,10 @@ const ( type Client struct { // Key is the account key used to register with a CA and sign requests. // Key.Public() must return a *rsa.PublicKey or *ecdsa.PublicKey. + // + // The following algorithms are supported: + // RS256, ES256, ES384 and ES512. + // See RFC7518 for more details about the algorithms. Key crypto.Signer // HTTPClient optionally specifies an HTTP client to use @@ -76,6 +93,22 @@ type Client struct { // will have no effect. DirectoryURL string + // RetryBackoff computes the duration after which the nth retry of a failed request + // should occur. The value of n for the first call on failure is 1. + // The values of r and resp are the request and response of the last failed attempt. + // If the returned value is negative or zero, no more retries are done and an error + // is returned to the caller of the original method. + // + // Requests which result in a 4xx client error are not retried, + // except for 400 Bad Request due to "bad nonce" errors and 429 Too Many Requests. + // + // If RetryBackoff is nil, a truncated exponential backoff algorithm + // with the ceiling of 10 seconds is used, where each subsequent retry n + // is done after either ("Retry-After" + jitter) or (2^n seconds + jitter), + // preferring the former if "Retry-After" header is found in the resp. + // The jitter is a random value up to 1 second. + RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration + dirMu sync.Mutex // guards writes to dir dir *Directory // cached result of Client's Discover method @@ -99,15 +132,12 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) { if dirURL == "" { dirURL = LetsEncryptURL } - res, err := c.get(ctx, dirURL) + res, err := c.get(ctx, dirURL, wantStatus(http.StatusOK)) if err != nil { return Directory{}, err } defer res.Body.Close() c.addNonce(res.Header) - if res.StatusCode != http.StatusOK { - return Directory{}, responseError(res) - } var v struct { Reg string `json:"new-reg"` @@ -166,14 +196,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, req.NotAfter = now.Add(exp).Format(time.RFC3339) } - res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req) + res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated)) if err != nil { return nil, "", err } defer res.Body.Close() - if res.StatusCode != http.StatusCreated { - return nil, "", responseError(res) - } curl := res.Header.Get("Location") // cert permanent URL if res.ContentLength == 0 { @@ -196,26 +223,11 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration, // Callers are encouraged to parse the returned value to ensure the certificate is valid // and has expected features. func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) { - for { - res, err := c.get(ctx, url) - if err != nil { - return nil, err - } - defer res.Body.Close() - if res.StatusCode == http.StatusOK { - return c.responseCert(ctx, res, bundle) - } - if res.StatusCode > 299 { - return nil, responseError(res) - } - d := retryAfter(res.Header.Get("Retry-After"), 3*time.Second) - select { - case <-time.After(d): - // retry - case <-ctx.Done(): - return nil, ctx.Err() - } + res, err := c.get(ctx, url, wantStatus(http.StatusOK)) + if err != nil { + return nil, err } + return c.responseCert(ctx, res, bundle) } // RevokeCert revokes a previously issued certificate cert, provided in DER format. @@ -241,14 +253,11 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, if key == nil { key = c.Key } - res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body) + res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK)) if err != nil { return err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return responseError(res) - } return nil } @@ -329,14 +338,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, Resource: "new-authz", Identifier: authzID{Type: "dns", Value: domain}, } - res, err := c.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req) + res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated)) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusCreated { - return nil, responseError(res) - } var v wireAuthz if err := json.NewDecoder(res.Body).Decode(&v); err != nil { @@ -353,14 +359,11 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, // If a caller needs to poll an authorization until its status is final, // see the WaitAuthorization method. func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) { - res, err := c.get(ctx, url) + res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { - return nil, responseError(res) - } var v wireAuthz if err := json.NewDecoder(res.Body).Decode(&v); err != nil { return nil, fmt.Errorf("acme: invalid response: %v", err) @@ -387,56 +390,58 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error { Status: "deactivated", Delete: true, } - res, err := c.retryPostJWS(ctx, c.Key, url, req) + res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK)) if err != nil { return err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return responseError(res) - } return nil } // WaitAuthorization polls an authorization at the given URL // until it is in one of the final states, StatusValid or StatusInvalid, -// or the context is done. +// the ACME CA responded with a 4xx error code, or the context is done. // // It returns a non-nil Authorization only if its Status is StatusValid. // In all other cases WaitAuthorization returns an error. // If the Status is StatusInvalid, the returned error is of type *AuthorizationError. func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) { - sleep := sleeper(ctx) for { - res, err := c.get(ctx, url) + res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) if err != nil { return nil, err } - retry := res.Header.Get("Retry-After") - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { - res.Body.Close() - if err := sleep(retry, 1); err != nil { - return nil, err - } - continue - } + var raw wireAuthz err = json.NewDecoder(res.Body).Decode(&raw) res.Body.Close() - if err != nil { - if err := sleep(retry, 0); err != nil { - return nil, err - } - continue - } - if raw.Status == StatusValid { + switch { + case err != nil: + // Skip and retry. + case raw.Status == StatusValid: return raw.authorization(url), nil - } - if raw.Status == StatusInvalid { + case raw.Status == StatusInvalid: return nil, raw.error(url) } - if err := sleep(retry, 0); err != nil { - return nil, err + + // Exponential backoff is implemented in c.get above. + // This is just to prevent continuously hitting the CA + // while waiting for a final authorization status. + d := retryAfter(res.Header.Get("Retry-After")) + if d == 0 { + // Given that the fastest challenges TLS-SNI and HTTP-01 + // require a CA to make at least 1 network round trip + // and most likely persist a challenge state, + // this default delay seems reasonable. + d = time.Second + } + t := time.NewTimer(d) + select { + case <-ctx.Done(): + t.Stop() + return nil, ctx.Err() + case <-t.C: + // Retry. } } } @@ -445,14 +450,11 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat // // A client typically polls a challenge status using this method. func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) { - res, err := c.get(ctx, url) + res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted)) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { - return nil, responseError(res) - } v := wireChallenge{URI: url} if err := json.NewDecoder(res.Body).Decode(&v); err != nil { return nil, fmt.Errorf("acme: invalid response: %v", err) @@ -479,16 +481,14 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error Type: chal.Type, Auth: auth, } - res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req) + res, err := c.post(ctx, c.Key, chal.URI, req, wantStatus( + http.StatusOK, // according to the spec + http.StatusAccepted, // Let's Encrypt: see https://goo.gl/WsJ7VT (acme-divergences.md) + )) if err != nil { return nil, err } defer res.Body.Close() - // Note: the protocol specifies 200 as the expected response code, but - // letsencrypt seems to be returning 202. - if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted { - return nil, responseError(res) - } var v wireChallenge if err := json.NewDecoder(res.Body).Decode(&v); err != nil { @@ -545,7 +545,7 @@ func (c *Client) HTTP01ChallengePath(token string) string { // If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. // // The returned certificate is valid for the next 24 hours and must be presented only when -// the server name of the client hello matches exactly the returned name value. +// the server name of the TLS ClientHello matches exactly the returned name value. func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { ka, err := keyAuth(c.Key.Public(), token) if err != nil { @@ -572,7 +572,7 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl // If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. // // The returned certificate is valid for the next 24 hours and must be presented only when -// the server name in the client hello matches exactly the returned name value. +// the server name in the TLS ClientHello matches exactly the returned name value. func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tls.Certificate, name string, err error) { b := sha256.Sum256([]byte(token)) h := hex.EncodeToString(b[:]) @@ -593,6 +593,52 @@ func (c *Client) TLSSNI02ChallengeCert(token string, opt ...CertOption) (cert tl return cert, sanA, nil } +// TLSALPN01ChallengeCert creates a certificate for TLS-ALPN-01 challenge response. +// Servers can present the certificate to validate the challenge and prove control +// over a domain name. For more details on TLS-ALPN-01 see +// https://tools.ietf.org/html/draft-shoemaker-acme-tls-alpn-00#section-3 +// +// The token argument is a Challenge.Token value. +// If a WithKey option is provided, its private part signs the returned cert, +// and the public part is used to specify the signee. +// If no WithKey option is provided, a new ECDSA key is generated using P-256 curve. +// +// The returned certificate is valid for the next 24 hours and must be presented only when +// the server name in the TLS ClientHello matches the domain, and the special acme-tls/1 ALPN protocol +// has been specified. +func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption) (cert tls.Certificate, err error) { + ka, err := keyAuth(c.Key.Public(), token) + if err != nil { + return tls.Certificate{}, err + } + shasum := sha256.Sum256([]byte(ka)) + extValue, err := asn1.Marshal(shasum[:]) + if err != nil { + return tls.Certificate{}, err + } + acmeExtension := pkix.Extension{ + Id: idPeACMEIdentifierV1, + Critical: true, + Value: extValue, + } + + tmpl := defaultTLSChallengeCertTemplate() + + var newOpt []CertOption + for _, o := range opt { + switch o := o.(type) { + case *certOptTemplate: + t := *(*x509.Certificate)(o) // shallow copy is ok + tmpl = &t + default: + newOpt = append(newOpt, o) + } + } + tmpl.ExtraExtensions = append(tmpl.ExtraExtensions, acmeExtension) + newOpt = append(newOpt, WithTemplate(tmpl)) + return tlsChallengeCert([]string{domain}, newOpt) +} + // doReg sends all types of registration requests. // The type of request is identified by typ argument, which is a "resource" // in the ACME spec terms. @@ -612,14 +658,15 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun req.Contact = acct.Contact req.Agreement = acct.AgreedTerms } - res, err := c.retryPostJWS(ctx, c.Key, url, req) + res, err := c.post(ctx, c.Key, url, req, wantStatus( + http.StatusOK, // updates and deletes + http.StatusCreated, // new account creation + http.StatusAccepted, // Let's Encrypt divergent implementation + )) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode < 200 || res.StatusCode > 299 { - return nil, responseError(res) - } var v struct { Contact []string @@ -649,59 +696,6 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun }, nil } -// retryPostJWS will retry calls to postJWS if there is a badNonce error, -// clearing the stored nonces after each error. -// If the response was 4XX-5XX, then responseError is called on the body, -// the body is closed, and the error returned. -func (c *Client) retryPostJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) { - sleep := sleeper(ctx) - for { - res, err := c.postJWS(ctx, key, url, body) - if err != nil { - return nil, err - } - // handle errors 4XX-5XX with responseError - if res.StatusCode >= 400 && res.StatusCode <= 599 { - err := responseError(res) - res.Body.Close() - // according to spec badNonce is urn:ietf:params:acme:error:badNonce - // however, acme servers in the wild return their version of the error - // https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4 - if ae, ok := err.(*Error); ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") { - // clear any nonces that we might've stored that might now be - // considered bad - c.clearNonces() - retry := res.Header.Get("Retry-After") - if err := sleep(retry, 1); err != nil { - return nil, err - } - continue - } - return nil, err - } - return res, nil - } -} - -// postJWS signs the body with the given key and POSTs it to the provided url. -// The body argument must be JSON-serializable. -func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) { - nonce, err := c.popNonce(ctx, url) - if err != nil { - return nil, err - } - b, err := jwsEncodeJSON(body, key, nonce) - if err != nil { - return nil, err - } - res, err := c.post(ctx, url, "application/jose+json", bytes.NewReader(b)) - if err != nil { - return nil, err - } - c.addNonce(res.Header) - return res, nil -} - // popNonce returns a nonce value previously stored with c.addNonce // or fetches a fresh one from the given URL. func (c *Client) popNonce(ctx context.Context, url string) (string, error) { @@ -742,58 +736,12 @@ func (c *Client) addNonce(h http.Header) { c.nonces[v] = struct{}{} } -func (c *Client) httpClient() *http.Client { - if c.HTTPClient != nil { - return c.HTTPClient - } - return http.DefaultClient -} - -func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) { - req, err := http.NewRequest("GET", urlStr, nil) - if err != nil { - return nil, err - } - return c.do(ctx, req) -} - -func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) { - req, err := http.NewRequest("HEAD", urlStr, nil) - if err != nil { - return nil, err - } - return c.do(ctx, req) -} - -func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) { - req, err := http.NewRequest("POST", urlStr, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", contentType) - return c.do(ctx, req) -} - -func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) { - res, err := c.httpClient().Do(req.WithContext(ctx)) - if err != nil { - select { - case <-ctx.Done(): - // Prefer the unadorned context error. - // (The acme package had tests assuming this, previously from ctxhttp's - // behavior, predating net/http supporting contexts natively) - // TODO(bradfitz): reconsider this in the future. But for now this - // requires no test updates. - return nil, ctx.Err() - default: - return nil, err - } - } - return res, nil -} - func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) { - resp, err := c.head(ctx, url) + r, err := http.NewRequest("HEAD", url, nil) + if err != nil { + return "", err + } + resp, err := c.doNoRetry(ctx, r) if err != nil { return "", err } @@ -845,24 +793,6 @@ func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bo return cert, nil } -// responseError creates an error of Error type from resp. -func responseError(resp *http.Response) error { - // don't care if ReadAll returns an error: - // json.Unmarshal will fail in that case anyway - b, _ := ioutil.ReadAll(resp.Body) - e := &wireError{Status: resp.StatusCode} - if err := json.Unmarshal(b, e); err != nil { - // this is not a regular error response: - // populate detail with anything we received, - // e.Status will already contain HTTP response code value - e.Detail = string(b) - if e.Detail == "" { - e.Detail = resp.Status - } - } - return e.error(resp.Header) -} - // chainCert fetches CA certificate chain recursively by following "up" links. // Each recursive call increments the depth by 1, resulting in an error // if the recursion level reaches maxChainLen. @@ -873,14 +803,11 @@ func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte return nil, errors.New("acme: certificate chain is too deep") } - res, err := c.get(ctx, url) + res, err := c.get(ctx, url, wantStatus(http.StatusOK)) if err != nil { return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return nil, responseError(res) - } b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1)) if err != nil { return nil, err @@ -925,65 +852,6 @@ func linkHeader(h http.Header, rel string) []string { return links } -// sleeper returns a function that accepts the Retry-After HTTP header value -// and an increment that's used with backoff to increasingly sleep on -// consecutive calls until the context is done. If the Retry-After header -// cannot be parsed, then backoff is used with a maximum sleep time of 10 -// seconds. -func sleeper(ctx context.Context) func(ra string, inc int) error { - var count int - return func(ra string, inc int) error { - count += inc - d := backoff(count, 10*time.Second) - d = retryAfter(ra, d) - wakeup := time.NewTimer(d) - defer wakeup.Stop() - select { - case <-ctx.Done(): - return ctx.Err() - case <-wakeup.C: - return nil - } - } -} - -// retryAfter parses a Retry-After HTTP header value, -// trying to convert v into an int (seconds) or use http.ParseTime otherwise. -// It returns d if v cannot be parsed. -func retryAfter(v string, d time.Duration) time.Duration { - if i, err := strconv.Atoi(v); err == nil { - return time.Duration(i) * time.Second - } - t, err := http.ParseTime(v) - if err != nil { - return d - } - return t.Sub(timeNow()) -} - -// backoff computes a duration after which an n+1 retry iteration should occur -// using truncated exponential backoff algorithm. -// -// The n argument is always bounded between 0 and 30. -// The max argument defines upper bound for the returned value. -func backoff(n int, max time.Duration) time.Duration { - if n < 0 { - n = 0 - } - if n > 30 { - n = 30 - } - var d time.Duration - if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil { - d = time.Duration(x.Int64()) * time.Millisecond - } - d += time.Duration(1< max { - return max - } - return d -} - // keyAuth generates a key authorization string for a given token. func keyAuth(pub crypto.PublicKey, token string) (string, error) { th, err := JWKThumbprint(pub) @@ -993,15 +861,25 @@ func keyAuth(pub crypto.PublicKey, token string) (string, error) { return fmt.Sprintf("%s.%s", token, th), nil } +// defaultTLSChallengeCertTemplate is a template used to create challenge certs for TLS challenges. +func defaultTLSChallengeCertTemplate() *x509.Certificate { + return &x509.Certificate{ + SerialNumber: big.NewInt(1), + NotBefore: time.Now(), + NotAfter: time.Now().Add(24 * time.Hour), + BasicConstraintsValid: true, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + } +} + // tlsChallengeCert creates a temporary certificate for TLS-SNI challenges // with the given SANs and auto-generated public/private key pair. // The Subject Common Name is set to the first SAN to aid debugging. // To create a cert with a custom key pair, specify WithKey option. func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { - var ( - key crypto.Signer - tmpl *x509.Certificate - ) + var key crypto.Signer + tmpl := defaultTLSChallengeCertTemplate() for _, o := range opt { switch o := o.(type) { case *certOptKey: @@ -1010,7 +888,7 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { } key = o.key case *certOptTemplate: - var t = *(*x509.Certificate)(o) // shallow copy is ok + t := *(*x509.Certificate)(o) // shallow copy is ok tmpl = &t default: // package's fault, if we let this happen: @@ -1023,16 +901,6 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) { return tls.Certificate{}, err } } - if tmpl == nil { - tmpl = &x509.Certificate{ - SerialNumber: big.NewInt(1), - NotBefore: time.Now(), - NotAfter: time.Now().Add(24 * time.Hour), - BasicConstraintsValid: true, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - } - } tmpl.DNSNames = san if len(san) > 0 { tmpl.Subject.CommonName = san[0] diff --git a/vendor/golang.org/x/crypto/acme/acme_test.go b/vendor/golang.org/x/crypto/acme/acme_test.go index 89f2efaa..ef1fe478 100644 --- a/vendor/golang.org/x/crypto/acme/acme_test.go +++ b/vendor/golang.org/x/crypto/acme/acme_test.go @@ -13,9 +13,9 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/base64" + "encoding/hex" "encoding/json" "fmt" - "io/ioutil" "math/big" "net/http" "net/http/httptest" @@ -485,95 +485,98 @@ func TestGetAuthorization(t *testing.T) { } func TestWaitAuthorization(t *testing.T) { - var count int - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - count++ - w.Header().Set("Retry-After", "0") - if count > 1 { - fmt.Fprintf(w, `{"status":"valid"}`) - return + t.Run("wait loop", func(t *testing.T) { + var count int + authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) { + count++ + w.Header().Set("Retry-After", "0") + if count > 1 { + fmt.Fprintf(w, `{"status":"valid"}`) + return + } + fmt.Fprintf(w, `{"status":"pending"}`) + }) + if err != nil { + t.Fatalf("non-nil error: %v", err) } - fmt.Fprintf(w, `{"status":"pending"}`) - })) + if authz == nil { + t.Fatal("authz is nil") + } + }) + 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) + } + }) + for _, code := range []int{http.StatusTooManyRequests, http.StatusInternalServerError} { + t.Run(fmt.Sprintf("retriable %d error", code), func(t *testing.T) { + var count int + authz, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) { + count++ + w.Header().Set("Retry-After", "0") + if count > 1 { + fmt.Fprintf(w, `{"status":"valid"}`) + return + } + w.WriteHeader(code) + }) + if err != nil { + t.Fatalf("non-nil error: %v", err) + } + if authz == nil { + t.Fatal("authz is nil") + } + }) + } + t.Run("context cancel", func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) + defer cancel() + _, err := runWaitAuthorization(ctx, t, func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Retry-After", "60") + fmt.Fprintf(w, `{"status":"pending"}`) + }) + if err == nil { + t.Error("err is nil") + } + }) +} +func runWaitAuthorization(ctx context.Context, t *testing.T, h http.HandlerFunc) (*Authorization, error) { + t.Helper() + ts := httptest.NewServer(h) defer ts.Close() - type res struct { authz *Authorization err error } - done := make(chan res) - defer close(done) + ch := make(chan res, 1) go func() { var client Client - a, err := client.WaitAuthorization(context.Background(), ts.URL) - done <- res{a, err} + a, err := client.WaitAuthorization(ctx, ts.URL) + ch <- res{a, err} }() - - select { - case <-time.After(5 * time.Second): - t.Fatal("WaitAuthz took too long to return") - case res := <-done: - if res.err != nil { - t.Fatalf("res.err = %v", res.err) - } - if res.authz == nil { - t.Fatal("res.authz is nil") - } - } -} - -func TestWaitAuthorizationInvalid(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, `{"status":"invalid"}`) - })) - defer ts.Close() - - res := make(chan error) - defer close(res) - go func() { - var client Client - _, err := client.WaitAuthorization(context.Background(), ts.URL) - res <- err - }() - select { case <-time.After(3 * time.Second): - t.Fatal("WaitAuthz took too long to return") - case err := <-res: - if err == nil { - t.Error("err is nil") - } - if _, ok := err.(*AuthorizationError); !ok { - t.Errorf("err is %T; want *AuthorizationError", err) - } - } -} - -func TestWaitAuthorizationCancel(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Retry-After", "60") - fmt.Fprintf(w, `{"status":"pending"}`) - })) - defer ts.Close() - - res := make(chan error) - defer close(res) - go func() { - var client Client - ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) - defer cancel() - _, err := client.WaitAuthorization(ctx, ts.URL) - res <- err - }() - - select { - case <-time.After(time.Second): - t.Fatal("WaitAuthz took too long to return") - case err := <-res: - if err == nil { - t.Error("err is nil") - } + t.Fatal("WaitAuthorization took too long to return") + case v := <-ch: + return v.authz, v.err } + panic("runWaitAuthorization: out of select") } func TestRevokeAuthorization(t *testing.T) { @@ -600,7 +603,7 @@ func TestRevokeAuthorization(t *testing.T) { t.Errorf("req.Delete is false") } case "/2": - w.WriteHeader(http.StatusInternalServerError) + w.WriteHeader(http.StatusBadRequest) } })) defer ts.Close() @@ -821,7 +824,7 @@ func TestFetchCertRetry(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if count < 1 { w.Header().Set("Retry-After", "0") - w.WriteHeader(http.StatusAccepted) + w.WriteHeader(http.StatusTooManyRequests) count++ return } @@ -1068,44 +1071,6 @@ func TestNonce_postJWS(t *testing.T) { } } -func TestRetryPostJWS(t *testing.T) { - var count int - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - count++ - w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count)) - if r.Method == "HEAD" { - // We expect the client to do 2 head requests to fetch - // nonces, one to start and another after getting badNonce - return - } - - head, err := decodeJWSHead(r) - if err != nil { - t.Errorf("decodeJWSHead: %v", err) - } else if head.Nonce == "" { - t.Error("head.Nonce is empty") - } else if head.Nonce == "nonce1" { - // return a badNonce error to force the call to retry - w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`)) - return - } - // Make client.Authorize happy; we're not testing its result. - w.WriteHeader(http.StatusCreated) - w.Write([]byte(`{"status":"valid"}`)) - })) - defer ts.Close() - - client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}} - // This call will fail with badNonce, causing a retry - if _, err := client.Authorize(context.Background(), "example.com"); err != nil { - t.Errorf("client.Authorize 1: %v", err) - } - if count != 4 { - t.Errorf("total requests count: %d; want 4", count) - } -} - func TestLinkHeader(t *testing.T) { h := http.Header{"Link": { `;rel="next"`, @@ -1129,37 +1094,6 @@ func TestLinkHeader(t *testing.T) { } } -func TestErrorResponse(t *testing.T) { - s := `{ - "status": 400, - "type": "urn:acme:error:xxx", - "detail": "text" - }` - res := &http.Response{ - StatusCode: 400, - Status: "400 Bad Request", - Body: ioutil.NopCloser(strings.NewReader(s)), - Header: http.Header{"X-Foo": {"bar"}}, - } - err := responseError(res) - v, ok := err.(*Error) - if !ok { - t.Fatalf("err = %+v (%T); want *Error type", err, err) - } - if v.StatusCode != 400 { - t.Errorf("v.StatusCode = %v; want 400", v.StatusCode) - } - if v.ProblemType != "urn:acme:error:xxx" { - t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType) - } - if v.Detail != "text" { - t.Errorf("v.Detail = %q; want text", v.Detail) - } - if !reflect.DeepEqual(v.Header, res.Header) { - t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header) - } -} - func TestTLSSNI01ChallengeCert(t *testing.T) { const ( token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA" @@ -1227,6 +1161,58 @@ func TestTLSSNI02ChallengeCert(t *testing.T) { } } +func TestTLSALPN01ChallengeCert(t *testing.T) { + const ( + token = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA" + keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA." + testKeyECThumbprint + // echo -n | shasum -a 256 + h = "0420dbbd5eefe7b4d06eb9d1d9f5acb4c7cda27d320e4b30332f0b6cb441734ad7b0" + domain = "example.com" + ) + + extValue, err := hex.DecodeString(h) + if err != nil { + t.Fatal(err) + } + + client := &Client{Key: testKeyEC} + tlscert, err := client.TLSALPN01ChallengeCert(token, domain) + if err != nil { + t.Fatal(err) + } + + if n := len(tlscert.Certificate); n != 1 { + t.Fatalf("len(tlscert.Certificate) = %d; want 1", n) + } + cert, err := x509.ParseCertificate(tlscert.Certificate[0]) + if err != nil { + t.Fatal(err) + } + names := []string{domain} + if !reflect.DeepEqual(cert.DNSNames, names) { + t.Fatalf("cert.DNSNames = %v;\nwant %v", cert.DNSNames, names) + } + if cn := cert.Subject.CommonName; cn != domain { + t.Errorf("CommonName = %q; want %q", cn, domain) + } + acmeExts := []pkix.Extension{} + for _, ext := range cert.Extensions { + if idPeACMEIdentifierV1.Equal(ext.Id) { + acmeExts = append(acmeExts, ext) + } + } + if len(acmeExts) != 1 { + t.Errorf("acmeExts = %v; want exactly one", acmeExts) + } + if !acmeExts[0].Critical { + t.Errorf("acmeExt.Critical = %v; want true", acmeExts[0].Critical) + } + if bytes.Compare(acmeExts[0].Value, extValue) != 0 { + t.Errorf("acmeExt.Value = %v; want %v", acmeExts[0].Value, extValue) + } + +} + func TestTLSChallengeCertOpt(t *testing.T) { key, err := rsa.GenerateKey(rand.Reader, 512) if err != nil { @@ -1325,28 +1311,3 @@ func TestDNS01ChallengeRecord(t *testing.T) { t.Errorf("val = %q; want %q", val, value) } } - -func TestBackoff(t *testing.T) { - tt := []struct{ min, max time.Duration }{ - {time.Second, 2 * time.Second}, - {2 * time.Second, 3 * time.Second}, - {4 * time.Second, 5 * time.Second}, - {8 * time.Second, 9 * time.Second}, - } - for i, test := range tt { - d := backoff(i, time.Minute) - if d < test.min || test.max < d { - t.Errorf("%d: d = %v; want between %v and %v", i, d, test.min, test.max) - } - } - - min, max := time.Second, 2*time.Second - if d := backoff(-1, time.Minute); d < min || max < d { - t.Errorf("d = %v; want between %v and %v", d, min, max) - } - - bound := 10 * time.Second - if d := backoff(100, bound); d != bound { - t.Errorf("d = %v; want %v", d, bound) - } -} diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go index 263b2913..a50d9bfc 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go +++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go @@ -44,7 +44,7 @@ var createCertRetryAfter = time.Minute var pseudoRand *lockedMathRand func init() { - src := mathrand.NewSource(timeNow().UnixNano()) + src := mathrand.NewSource(time.Now().UnixNano()) pseudoRand = &lockedMathRand{rnd: mathrand.New(src)} } @@ -69,7 +69,7 @@ func HostWhitelist(hosts ...string) HostPolicy { } return func(_ context.Context, host string) error { if !whitelist[host] { - return errors.New("acme/autocert: host not configured") + return fmt.Errorf("acme/autocert: host %q not configured in HostWhitelist", host) } return nil } @@ -81,9 +81,9 @@ func defaultHostPolicy(context.Context, string) error { } // Manager is a stateful certificate manager built on top of acme.Client. -// It obtains and refreshes certificates automatically using "tls-sni-01", -// "tls-sni-02" and "http-01" challenge types, as well as providing them -// to a TLS server via tls.Config. +// It obtains and refreshes certificates automatically using "tls-alpn-01", +// "tls-sni-01", "tls-sni-02" and "http-01" challenge types, +// as well as providing them to a TLS server via tls.Config. // // You must specify a cache implementation, such as DirCache, // to reuse obtained certificates across program restarts. @@ -98,11 +98,11 @@ type Manager struct { // To always accept the terms, the callers can use AcceptTOS. Prompt func(tosURL string) bool - // Cache optionally stores and retrieves previously-obtained certificates. - // If nil, certs will only be cached for the lifetime of the Manager. + // Cache optionally stores and retrieves previously-obtained certificates + // and other state. If nil, certs will only be cached for the lifetime of + // the Manager. Multiple Managers can share the same Cache. // - // Manager passes the Cache certificates data encoded in PEM, with private/public - // parts combined in a single Cache.Put call, private key first. + // Using a persistent Cache, such as DirCache, is strongly recommended. Cache Cache // HostPolicy controls which domains the Manager will attempt @@ -127,8 +127,10 @@ type Manager struct { // Client is used to perform low-level operations, such as account registration // and requesting new certificates. + // // If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL - // directory endpoint and a newly-generated ECDSA P-256 key. + // as directory endpoint. If the Client.Key is nil, a new ECDSA P-256 key is + // generated and, if Cache is not nil, stored in cache. // // Mutating the field after the first call of GetCertificate method will have no effect. Client *acme.Client @@ -140,22 +142,30 @@ type Manager struct { // If the Client's account key is already registered, Email is not used. Email string - // ForceRSA makes the Manager generate certificates with 2048-bit RSA keys. + // ForceRSA used to make the Manager generate RSA certificates. It is now ignored. // - // If false, a default is used. Currently the default - // is EC-based keys using the P-256 curve. + // Deprecated: the Manager will request the correct type of certificate based + // on what each client supports. ForceRSA bool + // ExtraExtensions are used when generating a new CSR (Certificate Request), + // thus allowing customization of the resulting certificate. + // For instance, TLS Feature Extension (RFC 7633) can be used + // to prevent an OCSP downgrade attack. + // + // The field value is passed to crypto/x509.CreateCertificateRequest + // in the template's ExtraExtensions field as is. + ExtraExtensions []pkix.Extension + clientMu sync.Mutex client *acme.Client // initialized by acmeClient method stateMu sync.Mutex - state map[string]*certState // keyed by domain name + state map[certKey]*certState // renewal tracks the set of domains currently running renewal timers. - // It is keyed by domain name. renewalMu sync.Mutex - renewal map[string]*domainRenewal + renewal map[certKey]*domainRenewal // tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens. tokensMu sync.RWMutex @@ -167,21 +177,60 @@ type Manager struct { // to be provisioned. // The entries are stored for the duration of the authorization flow. httpTokens map[string][]byte - // certTokens contains temporary certificates for tls-sni challenges + // certTokens contains temporary certificates for tls-sni and tls-alpn challenges // and is keyed by token domain name, which matches server name of ClientHello. - // Keys always have ".acme.invalid" suffix. + // Keys always have ".acme.invalid" suffix for tls-sni. Otherwise, they are domain names + // for tls-alpn. // The entries are stored for the duration of the authorization flow. certTokens map[string]*tls.Certificate + // nowFunc, if not nil, returns the current time. This may be set for + // testing purposes. + nowFunc func() time.Time +} + +// certKey is the key by which certificates are tracked in state, renewal and cache. +type certKey struct { + domain string // without trailing dot + isRSA bool // RSA cert for legacy clients (as opposed to default ECDSA) + isToken bool // tls-based challenge token cert; key type is undefined regardless of isRSA +} + +func (c certKey) String() string { + if c.isToken { + return c.domain + "+token" + } + if c.isRSA { + return c.domain + "+rsa" + } + return c.domain +} + +// TLSConfig creates a new TLS config suitable for net/http.Server servers, +// supporting HTTP/2 and the tls-alpn-01 ACME challenge type. +func (m *Manager) TLSConfig() *tls.Config { + return &tls.Config{ + GetCertificate: m.GetCertificate, + NextProtos: []string{ + "h2", "http/1.1", // enable HTTP/2 + acme.ALPNProto, // enable tls-alpn ACME challenges + }, + } } // GetCertificate implements the tls.Config.GetCertificate hook. // It provides a TLS certificate for hello.ServerName host, including answering -// *.acme.invalid (TLS-SNI) challenges. All other fields of hello are ignored. +// tls-alpn-01 and *.acme.invalid (tls-sni-01 and tls-sni-02) challenges. +// All other fields of hello are ignored. // // If m.HostPolicy is non-nil, GetCertificate calls the policy before requesting // a new cert. A non-nil error returned from m.HostPolicy halts TLS negotiation. // The error is propagated back to the caller of GetCertificate and is user-visible. // This does not affect cached certs. See HostPolicy field description for more details. +// +// If GetCertificate is used directly, instead of via Manager.TLSConfig, package users will +// also have to add acme.ALPNProto to NextProtos for tls-alpn-01, or use HTTPHandler +// for http-01. (The tls-sni-* challenges have been deprecated by popular ACME providers +// due to security issues in the ecosystem.) func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { if m.Prompt == nil { return nil, errors.New("acme/autocert: Manager.Prompt not set") @@ -194,7 +243,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, if !strings.Contains(strings.Trim(name, "."), ".") { return nil, errors.New("acme/autocert: server name component count invalid") } - if strings.ContainsAny(name, `/\`) { + if strings.ContainsAny(name, `+/\`) { return nil, errors.New("acme/autocert: server name contains invalid character") } @@ -203,14 +252,17 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() - // check whether this is a token cert requested for TLS-SNI challenge - if strings.HasSuffix(name, ".acme.invalid") { + // Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge. + if wantsTokenCert(hello) { m.tokensMu.RLock() defer m.tokensMu.RUnlock() + // It's ok to use the same token cert key for both tls-sni and tls-alpn + // because there's always at most 1 token cert per on-going domain authorization. + // See m.verify for details. if cert := m.certTokens[name]; cert != nil { return cert, nil } - if cert, err := m.cacheGet(ctx, name); err == nil { + if cert, err := m.cacheGet(ctx, certKey{domain: name, isToken: true}); err == nil { return cert, nil } // TODO: cache error results? @@ -218,8 +270,11 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, } // regular domain - name = strings.TrimSuffix(name, ".") // golang.org/issue/18114 - cert, err := m.cert(ctx, name) + ck := certKey{ + domain: strings.TrimSuffix(name, "."), // golang.org/issue/18114 + isRSA: !supportsECDSA(hello), + } + cert, err := m.cert(ctx, ck) if err == nil { return cert, nil } @@ -231,14 +286,71 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, if err := m.hostPolicy()(ctx, name); err != nil { return nil, err } - cert, err = m.createCert(ctx, name) + cert, err = m.createCert(ctx, ck) if err != nil { return nil, err } - m.cachePut(ctx, name, cert) + m.cachePut(ctx, ck, cert) return cert, nil } +// wantsTokenCert reports whether a TLS request with SNI is made by a CA server +// for a challenge verification. +func wantsTokenCert(hello *tls.ClientHelloInfo) bool { + // tls-alpn-01 + if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto { + return true + } + // tls-sni-xx + return strings.HasSuffix(hello.ServerName, ".acme.invalid") +} + +func supportsECDSA(hello *tls.ClientHelloInfo) bool { + // The "signature_algorithms" extension, if present, limits the key exchange + // algorithms allowed by the cipher suites. See RFC 5246, section 7.4.1.4.1. + if hello.SignatureSchemes != nil { + ecdsaOK := false + schemeLoop: + for _, scheme := range hello.SignatureSchemes { + const tlsECDSAWithSHA1 tls.SignatureScheme = 0x0203 // constant added in Go 1.10 + switch scheme { + case tlsECDSAWithSHA1, tls.ECDSAWithP256AndSHA256, + tls.ECDSAWithP384AndSHA384, tls.ECDSAWithP521AndSHA512: + ecdsaOK = true + break schemeLoop + } + } + if !ecdsaOK { + return false + } + } + if hello.SupportedCurves != nil { + ecdsaOK := false + for _, curve := range hello.SupportedCurves { + if curve == tls.CurveP256 { + ecdsaOK = true + break + } + } + if !ecdsaOK { + return false + } + } + for _, suite := range hello.CipherSuites { + switch suite { + case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: + return true + } + } + return false +} + // HTTPHandler configures the Manager to provision ACME "http-01" challenge responses. // It returns an http.Handler that responds to the challenges and must be // running on port 80. If it receives a request that is not an ACME challenge, @@ -252,8 +364,8 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, // Because the fallback handler is run with unencrypted port 80 requests, // the fallback should not serve TLS-only requests. // -// If HTTPHandler is never called, the Manager will only use TLS SNI -// challenges for domain verification. +// If HTTPHandler is never called, the Manager will only use the "tls-alpn-01" +// challenge for domain verification. func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler { m.tokensMu.Lock() defer m.tokensMu.Unlock() @@ -304,16 +416,16 @@ func stripPort(hostport string) string { // cert returns an existing certificate either from m.state or cache. // If a certificate is found in cache but not in m.state, the latter will be filled // with the cached value. -func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, error) { +func (m *Manager) cert(ctx context.Context, ck certKey) (*tls.Certificate, error) { m.stateMu.Lock() - if s, ok := m.state[name]; ok { + if s, ok := m.state[ck]; ok { m.stateMu.Unlock() s.RLock() defer s.RUnlock() return s.tlscert() } defer m.stateMu.Unlock() - cert, err := m.cacheGet(ctx, name) + cert, err := m.cacheGet(ctx, ck) if err != nil { return nil, err } @@ -322,25 +434,25 @@ func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, erro return nil, errors.New("acme/autocert: private key cannot sign") } if m.state == nil { - m.state = make(map[string]*certState) + m.state = make(map[certKey]*certState) } s := &certState{ key: signer, cert: cert.Certificate, leaf: cert.Leaf, } - m.state[name] = s - go m.renew(name, s.key, s.leaf.NotAfter) + m.state[ck] = s + go m.renew(ck, s.key, s.leaf.NotAfter) return cert, nil } // cacheGet always returns a valid certificate, or an error otherwise. -// If a cached certficate exists but is not valid, ErrCacheMiss is returned. -func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate, error) { +// If a cached certificate exists but is not valid, ErrCacheMiss is returned. +func (m *Manager) cacheGet(ctx context.Context, ck certKey) (*tls.Certificate, error) { if m.Cache == nil { return nil, ErrCacheMiss } - data, err := m.Cache.Get(ctx, domain) + data, err := m.Cache.Get(ctx, ck.String()) if err != nil { return nil, err } @@ -371,7 +483,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate } // verify and create TLS cert - leaf, err := validCert(domain, pubDER, privKey) + leaf, err := validCert(ck, pubDER, privKey, m.now()) if err != nil { return nil, ErrCacheMiss } @@ -383,7 +495,7 @@ func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate return tlscert, nil } -func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Certificate) error { +func (m *Manager) cachePut(ctx context.Context, ck certKey, tlscert *tls.Certificate) error { if m.Cache == nil { return nil } @@ -415,7 +527,7 @@ func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Cert } } - return m.Cache.Put(ctx, domain, buf.Bytes()) + return m.Cache.Put(ctx, ck.String(), buf.Bytes()) } func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error { @@ -432,9 +544,9 @@ func encodeECDSAKey(w io.Writer, key *ecdsa.PrivateKey) error { // // If the domain is already being verified, it waits for the existing verification to complete. // Either way, createCert blocks for the duration of the whole process. -func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certificate, error) { +func (m *Manager) createCert(ctx context.Context, ck certKey) (*tls.Certificate, error) { // TODO: maybe rewrite this whole piece using sync.Once - state, err := m.certState(domain) + state, err := m.certState(ck) if err != nil { return nil, err } @@ -452,44 +564,44 @@ func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certifica defer state.Unlock() state.locked = false - der, leaf, err := m.authorizedCert(ctx, state.key, domain) + der, leaf, err := m.authorizedCert(ctx, state.key, ck) if err != nil { // Remove the failed state after some time, // making the manager call createCert again on the following TLS hello. time.AfterFunc(createCertRetryAfter, func() { - defer testDidRemoveState(domain) + defer testDidRemoveState(ck) m.stateMu.Lock() defer m.stateMu.Unlock() // Verify the state hasn't changed and it's still invalid // before deleting. - s, ok := m.state[domain] + s, ok := m.state[ck] if !ok { return } - if _, err := validCert(domain, s.cert, s.key); err == nil { + if _, err := validCert(ck, s.cert, s.key, m.now()); err == nil { return } - delete(m.state, domain) + delete(m.state, ck) }) return nil, err } state.cert = der state.leaf = leaf - go m.renew(domain, state.key, state.leaf.NotAfter) + go m.renew(ck, state.key, state.leaf.NotAfter) return state.tlscert() } // certState returns a new or existing certState. // If a new certState is returned, state.exist is false and the state is locked. // The returned error is non-nil only in the case where a new state could not be created. -func (m *Manager) certState(domain string) (*certState, error) { +func (m *Manager) certState(ck certKey) (*certState, error) { m.stateMu.Lock() defer m.stateMu.Unlock() if m.state == nil { - m.state = make(map[string]*certState) + m.state = make(map[certKey]*certState) } // existing state - if state, ok := m.state[domain]; ok { + if state, ok := m.state[ck]; ok { return state, nil } @@ -498,7 +610,7 @@ func (m *Manager) certState(domain string) (*certState, error) { err error key crypto.Signer ) - if m.ForceRSA { + if ck.isRSA { key, err = rsa.GenerateKey(rand.Reader, 2048) } else { key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -512,22 +624,22 @@ func (m *Manager) certState(domain string) (*certState, error) { locked: true, } state.Lock() // will be unlocked by m.certState caller - m.state[domain] = state + m.state[ck] = state return state, nil } // authorizedCert starts the domain ownership verification process and requests a new cert upon success. // The key argument is the certificate private key. -func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) { +func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) { client, err := m.acmeClient(ctx) if err != nil { return nil, nil, err } - if err := m.verify(ctx, client, domain); err != nil { + if err := m.verify(ctx, client, ck.domain); err != nil { return nil, nil, err } - csr, err := certRequest(key, domain) + csr, err := certRequest(key, ck.domain, m.ExtraExtensions) if err != nil { return nil, nil, err } @@ -535,25 +647,55 @@ func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain if err != nil { return nil, nil, err } - leaf, err = validCert(domain, der, key) + leaf, err = validCert(ck, der, key, m.now()) if err != nil { return nil, nil, err } return der, leaf, nil } +// revokePendingAuthz revokes all authorizations idenfied by the elements of uri slice. +// It ignores revocation errors. +func (m *Manager) revokePendingAuthz(ctx context.Context, uri []string) { + client, err := m.acmeClient(ctx) + if err != nil { + return + } + for _, u := range uri { + client.RevokeAuthorization(ctx, u) + } +} + // verify runs the identifier (domain) authorization flow // using each applicable ACME challenge type. func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error { // The list of challenge types we'll try to fulfill // in this specific order. - challengeTypes := []string{"tls-sni-02", "tls-sni-01"} + challengeTypes := []string{"tls-alpn-01", "tls-sni-02", "tls-sni-01"} m.tokensMu.RLock() if m.tryHTTP01 { challengeTypes = append(challengeTypes, "http-01") } m.tokensMu.RUnlock() + // Keep track of pending authzs and revoke the ones that did not validate. + pendingAuthzs := make(map[string]bool) + defer func() { + var uri []string + for k, pending := range pendingAuthzs { + if pending { + uri = append(uri, k) + } + } + if len(uri) > 0 { + // Use "detached" background context. + // The revocations need not happen in the current verification flow. + go m.revokePendingAuthz(context.Background(), uri) + } + }() + + // errs accumulates challenge failure errors, printed if all fail + errs := make(map[*acme.Challenge]error) var nextTyp int // challengeType index of the next challenge type to try for { // Start domain authorization and get the challenge. @@ -570,6 +712,8 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI) } + pendingAuthzs[authz.URI] = true + // Pick the next preferred challenge. var chal *acme.Challenge for chal == nil && nextTyp < len(challengeTypes) { @@ -577,28 +721,44 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string nextTyp++ } if chal == nil { - return fmt.Errorf("acme/autocert: unable to authorize %q; tried %q", domain, challengeTypes) + errorMsg := fmt.Sprintf("acme/autocert: unable to authorize %q", domain) + for chal, err := range errs { + errorMsg += fmt.Sprintf("; challenge %q failed with error: %v", chal.Type, err) + } + return errors.New(errorMsg) } - cleanup, err := m.fulfill(ctx, client, chal) + cleanup, err := m.fulfill(ctx, client, chal, domain) if err != nil { + errs[chal] = err continue } defer cleanup() if _, err := client.Accept(ctx, chal); err != nil { + errs[chal] = err continue } // A challenge is fulfilled and accepted: wait for the CA to validate. - if _, err := client.WaitAuthorization(ctx, authz.URI); err == nil { - return nil + if _, err := client.WaitAuthorization(ctx, authz.URI); err != nil { + errs[chal] = err + continue } + delete(pendingAuthzs, authz.URI) + return nil } } // fulfill provisions a response to the challenge chal. // The cleanup is non-nil only if provisioning succeeded. -func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge) (cleanup func(), err error) { +func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge, domain string) (cleanup func(), err error) { switch chal.Type { + case "tls-alpn-01": + cert, err := client.TLSALPN01ChallengeCert(chal.Token, domain) + if err != nil { + return nil, err + } + m.putCertToken(ctx, domain, &cert) + return func() { go m.deleteCertToken(domain) }, nil case "tls-sni-01": cert, name, err := client.TLSSNI01ChallengeCert(chal.Token) if err != nil { @@ -634,8 +794,8 @@ func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge { return nil } -// putCertToken stores the cert under the named key in both m.certTokens map -// and m.Cache. +// putCertToken stores the token certificate with the specified name +// in both m.certTokens map and m.Cache. func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) { m.tokensMu.Lock() defer m.tokensMu.Unlock() @@ -643,17 +803,18 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi m.certTokens = make(map[string]*tls.Certificate) } m.certTokens[name] = cert - m.cachePut(ctx, name, cert) + m.cachePut(ctx, certKey{domain: name, isToken: true}, cert) } -// deleteCertToken removes the token certificate for the specified domain name +// 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 { - m.Cache.Delete(context.Background(), name) + ck := certKey{domain: name, isToken: true} + m.Cache.Delete(context.Background(), ck.String()) } } @@ -704,7 +865,7 @@ func (m *Manager) deleteHTTPToken(tokenPath string) { // httpTokenCacheKey returns a key at which an http-01 token value may be stored // in the Manager's optional Cache. func httpTokenCacheKey(tokenPath string) string { - return "http-01-" + path.Base(tokenPath) + return path.Base(tokenPath) + "+http-01" } // renew starts a cert renewal timer loop, one per domain. @@ -715,18 +876,18 @@ func httpTokenCacheKey(tokenPath string) string { // // The key argument is a certificate private key. // The exp argument is the cert expiration time (NotAfter). -func (m *Manager) renew(domain string, key crypto.Signer, exp time.Time) { +func (m *Manager) renew(ck certKey, key crypto.Signer, exp time.Time) { m.renewalMu.Lock() defer m.renewalMu.Unlock() - if m.renewal[domain] != nil { + if m.renewal[ck] != nil { // another goroutine is already on it return } if m.renewal == nil { - m.renewal = make(map[string]*domainRenewal) + m.renewal = make(map[certKey]*domainRenewal) } - dr := &domainRenewal{m: m, domain: domain, key: key} - m.renewal[domain] = dr + dr := &domainRenewal{m: m, ck: ck, key: key} + m.renewal[ck] = dr dr.start(exp) } @@ -742,7 +903,10 @@ func (m *Manager) stopRenew() { } func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) { - const keyName = "acme_account.key" + const keyName = "acme_account+key" + + // Previous versions of autocert stored the value under a different key. + const legacyKeyName = "acme_account.key" genKey := func() (*ecdsa.PrivateKey, error) { return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -753,6 +917,9 @@ func (m *Manager) accountKey(ctx context.Context) (crypto.Signer, error) { } data, err := m.Cache.Get(ctx, keyName) + if err == ErrCacheMiss { + data, err = m.Cache.Get(ctx, legacyKeyName) + } if err == ErrCacheMiss { key, err := genKey() if err != nil { @@ -824,6 +991,13 @@ func (m *Manager) renewBefore() time.Duration { return 720 * time.Hour // 30 days } +func (m *Manager) now() time.Time { + if m.nowFunc != nil { + return m.nowFunc() + } + return time.Now() +} + // certState is ready when its mutex is unlocked for reading. type certState struct { sync.RWMutex @@ -849,12 +1023,12 @@ func (s *certState) tlscert() (*tls.Certificate, error) { }, nil } -// certRequest creates a certificate request for the given common name cn -// and optional SANs. -func certRequest(key crypto.Signer, cn string, san ...string) ([]byte, error) { +// certRequest generates a CSR for the given common name cn and optional SANs. +func certRequest(key crypto.Signer, cn string, ext []pkix.Extension, san ...string) ([]byte, error) { req := &x509.CertificateRequest{ - Subject: pkix.Name{CommonName: cn}, - DNSNames: san, + Subject: pkix.Name{CommonName: cn}, + DNSNames: san, + ExtraExtensions: ext, } return x509.CreateCertificateRequest(rand.Reader, req, key) } @@ -885,12 +1059,12 @@ func parsePrivateKey(der []byte) (crypto.Signer, error) { return nil, errors.New("acme/autocert: failed to parse private key") } -// validCert parses a cert chain provided as der argument and verifies the leaf, der[0], -// corresponds to the private key, as well as the domain match and expiration dates. -// It doesn't do any revocation checking. +// validCert parses a cert chain provided as der argument and verifies the leaf and der[0] +// correspond to the private key, the domain and key type match, and expiration dates +// are valid. It doesn't do any revocation checking. // // The returned value is the verified leaf cert. -func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certificate, err error) { +func validCert(ck certKey, der [][]byte, key crypto.Signer, now time.Time) (leaf *x509.Certificate, err error) { // parse public part(s) var n int for _, b := range der { @@ -902,22 +1076,21 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi n += copy(pub[n:], b) } x509Cert, err := x509.ParseCertificates(pub) - if len(x509Cert) == 0 { + if err != nil || len(x509Cert) == 0 { return nil, errors.New("acme/autocert: no public key found") } // verify the leaf is not expired and matches the domain name leaf = x509Cert[0] - now := timeNow() if now.Before(leaf.NotBefore) { return nil, errors.New("acme/autocert: certificate is not valid yet") } if now.After(leaf.NotAfter) { return nil, errors.New("acme/autocert: expired certificate") } - if err := leaf.VerifyHostname(domain); err != nil { + if err := leaf.VerifyHostname(ck.domain); err != nil { return nil, err } - // ensure the leaf corresponds to the private key + // ensure the leaf corresponds to the private key and matches the certKey type switch pub := leaf.PublicKey.(type) { case *rsa.PublicKey: prv, ok := key.(*rsa.PrivateKey) @@ -927,6 +1100,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi if pub.N.Cmp(prv.N) != 0 { return nil, errors.New("acme/autocert: private key does not match public key") } + if !ck.isRSA && !ck.isToken { + return nil, errors.New("acme/autocert: key type does not match expected value") + } case *ecdsa.PublicKey: prv, ok := key.(*ecdsa.PrivateKey) if !ok { @@ -935,6 +1111,9 @@ func validCert(domain string, der [][]byte, key crypto.Signer) (leaf *x509.Certi if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 { return nil, errors.New("acme/autocert: private key does not match public key") } + if ck.isRSA && !ck.isToken { + return nil, errors.New("acme/autocert: key type does not match expected value") + } default: return nil, errors.New("acme/autocert: unknown public key algorithm") } @@ -955,8 +1134,6 @@ func (r *lockedMathRand) int63n(max int64) int64 { // For easier testing. var ( - timeNow = time.Now - // Called when a state is removed. - testDidRemoveState = func(domain string) {} + testDidRemoveState = func(certKey) {} ) diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go b/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go index 2da1912e..95e12e16 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go +++ b/vendor/golang.org/x/crypto/acme/autocert/autocert_test.go @@ -5,6 +5,7 @@ package autocert import ( + "bytes" "context" "crypto" "crypto/ecdsa" @@ -14,11 +15,13 @@ import ( "crypto/tls" "crypto/x509" "crypto/x509/pkix" + "encoding/asn1" "encoding/base64" "encoding/json" "fmt" "html/template" "io" + "io/ioutil" "math/big" "net/http" "net/http/httptest" @@ -29,6 +32,13 @@ import ( "time" "golang.org/x/crypto/acme" + "golang.org/x/crypto/acme/autocert/internal/acmetest" +) + +var ( + exampleDomain = "example.org" + exampleCertKey = certKey{domain: exampleDomain} + exampleCertKeyRSA = certKey{domain: exampleDomain, isRSA: true} ) var discoTmpl = template.Must(template.New("disco").Parse(`{ @@ -64,6 +74,7 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{ }`)) type memCache struct { + t *testing.T mu sync.Mutex keyData map[string][]byte } @@ -79,7 +90,26 @@ func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) { return v, nil } +// filenameSafe returns whether all characters in s are printable ASCII +// and safe to use in a filename on most filesystems. +func filenameSafe(s string) bool { + for _, c := range s { + if c < 0x20 || c > 0x7E { + return false + } + switch c { + case '\\', '/', ':', '*', '?', '"', '<', '>', '|': + return false + } + } + return true +} + func (m *memCache) Put(ctx context.Context, key string, data []byte) error { + if !filenameSafe(key) { + m.t.Errorf("invalid characters in cache key %q", key) + } + m.mu.Lock() defer m.mu.Unlock() @@ -95,12 +125,29 @@ func (m *memCache) Delete(ctx context.Context, key string) error { return nil } -func newMemCache() *memCache { +func newMemCache(t *testing.T) *memCache { return &memCache{ + t: t, keyData: make(map[string][]byte), } } +func (m *memCache) numCerts() int { + m.mu.Lock() + defer m.mu.Unlock() + + res := 0 + for key := range m.keyData { + if strings.HasSuffix(key, "+token") || + strings.HasSuffix(key, "+key") || + strings.HasSuffix(key, "+http-01") { + continue + } + res++ + } + return res +} + func dummyCert(pub interface{}, san ...string) ([]byte, error) { return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...) } @@ -137,53 +184,58 @@ func decodePayload(v interface{}, r io.Reader) error { return json.Unmarshal(payload, v) } +func clientHelloInfo(sni string, ecdsaSupport bool) *tls.ClientHelloInfo { + hello := &tls.ClientHelloInfo{ + ServerName: sni, + CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}, + } + if ecdsaSupport { + hello.CipherSuites = append(hello.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305) + } + return hello +} + func TestGetCertificate(t *testing.T) { man := &Manager{Prompt: AcceptTOS} defer man.stopRenew() - hello := &tls.ClientHelloInfo{ServerName: "example.org"} + hello := clientHelloInfo("example.org", true) testGetCertificate(t, man, "example.org", hello) } func TestGetCertificate_trailingDot(t *testing.T) { man := &Manager{Prompt: AcceptTOS} defer man.stopRenew() - hello := &tls.ClientHelloInfo{ServerName: "example.org."} + hello := clientHelloInfo("example.org.", true) testGetCertificate(t, man, "example.org", hello) } func TestGetCertificate_ForceRSA(t *testing.T) { man := &Manager{ Prompt: AcceptTOS, - Cache: newMemCache(), + Cache: newMemCache(t), ForceRSA: true, } defer man.stopRenew() - hello := &tls.ClientHelloInfo{ServerName: "example.org"} - testGetCertificate(t, man, "example.org", hello) + hello := clientHelloInfo(exampleDomain, true) + testGetCertificate(t, man, exampleDomain, hello) - cert, err := man.cacheGet(context.Background(), "example.org") + // ForceRSA was deprecated and is now ignored. + cert, err := man.cacheGet(context.Background(), exampleCertKey) if err != nil { t.Fatalf("man.cacheGet: %v", err) } - if _, ok := cert.PrivateKey.(*rsa.PrivateKey); !ok { - t.Errorf("cert.PrivateKey is %T; want *rsa.PrivateKey", cert.PrivateKey) + if _, ok := cert.PrivateKey.(*ecdsa.PrivateKey); !ok { + t.Errorf("cert.PrivateKey is %T; want *ecdsa.PrivateKey", cert.PrivateKey) } } func TestGetCertificate_nilPrompt(t *testing.T) { man := &Manager{} defer man.stopRenew() - url, finish := startACMEServerStub(t, man, "example.org") + url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org") defer finish() - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } - man.Client = &acme.Client{ - Key: key, - DirectoryURL: url, - } - hello := &tls.ClientHelloInfo{ServerName: "example.org"} + man.Client = &acme.Client{DirectoryURL: url} + hello := clientHelloInfo("example.org", true) if _, err := man.GetCertificate(hello); err == nil { t.Error("got certificate for example.org; wanted error") } @@ -197,7 +249,7 @@ func TestGetCertificate_expiredCache(t *testing.T) { } tmpl := &x509.Certificate{ SerialNumber: big.NewInt(1), - Subject: pkix.Name{CommonName: "example.org"}, + Subject: pkix.Name{CommonName: exampleDomain}, NotAfter: time.Now(), } pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk) @@ -209,16 +261,16 @@ func TestGetCertificate_expiredCache(t *testing.T) { PrivateKey: pk, } - man := &Manager{Prompt: AcceptTOS, Cache: newMemCache()} + man := &Manager{Prompt: AcceptTOS, Cache: newMemCache(t)} defer man.stopRenew() - if err := man.cachePut(context.Background(), "example.org", tlscert); err != nil { + if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil { t.Fatalf("man.cachePut: %v", err) } // The expired cached cert should trigger a new cert issuance // and return without an error. - hello := &tls.ClientHelloInfo{ServerName: "example.org"} - testGetCertificate(t, man, "example.org", hello) + hello := clientHelloInfo(exampleDomain, true) + testGetCertificate(t, man, exampleDomain, hello) } func TestGetCertificate_failedAttempt(t *testing.T) { @@ -227,7 +279,6 @@ func TestGetCertificate_failedAttempt(t *testing.T) { })) defer ts.Close() - const example = "example.org" d := createCertRetryAfter f := testDidRemoveState defer func() { @@ -236,51 +287,168 @@ func TestGetCertificate_failedAttempt(t *testing.T) { }() createCertRetryAfter = 0 done := make(chan struct{}) - testDidRemoveState = func(domain string) { - if domain != example { - t.Errorf("testDidRemoveState: domain = %q; want %q", domain, example) + testDidRemoveState = func(ck certKey) { + if ck != exampleCertKey { + t.Errorf("testDidRemoveState: domain = %v; want %v", ck, exampleCertKey) } close(done) } - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } man := &Manager{ Prompt: AcceptTOS, Client: &acme.Client{ - Key: key, DirectoryURL: ts.URL, }, } defer man.stopRenew() - hello := &tls.ClientHelloInfo{ServerName: example} + hello := clientHelloInfo(exampleDomain, true) if _, err := man.GetCertificate(hello); err == nil { t.Error("GetCertificate: err is nil") } select { case <-time.After(5 * time.Second): - t.Errorf("took too long to remove the %q state", example) + t.Errorf("took too long to remove the %q state", exampleCertKey) case <-done: man.stateMu.Lock() defer man.stateMu.Unlock() - if v, exist := man.state[example]; exist { - t.Errorf("state exists for %q: %+v", example, v) + if v, exist := man.state[exampleCertKey]; exist { + t.Errorf("state exists for %v: %+v", exampleCertKey, v) } } } +// testGetCertificate_tokenCache tests the fallback of token certificate fetches +// to cache when Manager.certTokens misses. ecdsaSupport refers to the CA when +// verifying the certificate token. +func testGetCertificate_tokenCache(t *testing.T, ecdsaSupport bool) { + man1 := &Manager{ + Cache: newMemCache(t), + Prompt: AcceptTOS, + } + defer man1.stopRenew() + man2 := &Manager{ + Cache: man1.Cache, + Prompt: AcceptTOS, + } + defer man2.stopRenew() + + // Send the verification request to a different Manager from the one that + // initiated the authorization, when they share caches. + url, finish := startACMEServerStub(t, getCertificateFromManager(man2, ecdsaSupport), "example.org") + defer finish() + man1.Client = &acme.Client{DirectoryURL: url} + hello := clientHelloInfo("example.org", true) + if _, err := man1.GetCertificate(hello); err != nil { + t.Error(err) + } + if _, err := man2.GetCertificate(hello); err != nil { + t.Error(err) + } +} + +func TestGetCertificate_tokenCache(t *testing.T) { + t.Run("ecdsaSupport=true", func(t *testing.T) { + testGetCertificate_tokenCache(t, true) + }) + t.Run("ecdsaSupport=false", func(t *testing.T) { + testGetCertificate_tokenCache(t, false) + }) +} + +func TestGetCertificate_ecdsaVsRSA(t *testing.T) { + cache := newMemCache(t) + man := &Manager{Prompt: AcceptTOS, Cache: cache} + defer man.stopRenew() + url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org") + defer finish() + man.Client = &acme.Client{DirectoryURL: url} + + cert, err := man.GetCertificate(clientHelloInfo("example.org", true)) + if err != nil { + t.Error(err) + } + if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok { + t.Error("an ECDSA client was served a non-ECDSA certificate") + } + + cert, err = man.GetCertificate(clientHelloInfo("example.org", false)) + if err != nil { + t.Error(err) + } + if _, ok := cert.Leaf.PublicKey.(*rsa.PublicKey); !ok { + t.Error("a RSA client was served a non-RSA certificate") + } + + if _, err := man.GetCertificate(clientHelloInfo("example.org", true)); err != nil { + t.Error(err) + } + if _, err := man.GetCertificate(clientHelloInfo("example.org", false)); err != nil { + t.Error(err) + } + if numCerts := cache.numCerts(); numCerts != 2 { + t.Errorf("found %d certificates in cache; want %d", numCerts, 2) + } +} + +func TestGetCertificate_wrongCacheKeyType(t *testing.T) { + cache := newMemCache(t) + man := &Manager{Prompt: AcceptTOS, Cache: cache} + defer man.stopRenew() + url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), exampleDomain) + defer finish() + man.Client = &acme.Client{DirectoryURL: url} + + // Make an RSA cert and cache it without suffix. + pk, err := rsa.GenerateKey(rand.Reader, 512) + if err != nil { + t.Fatal(err) + } + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: exampleDomain}, + NotAfter: time.Now().Add(90 * 24 * time.Hour), + } + pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk) + if err != nil { + t.Fatal(err) + } + rsaCert := &tls.Certificate{ + Certificate: [][]byte{pub}, + PrivateKey: pk, + } + if err := man.cachePut(context.Background(), exampleCertKey, rsaCert); err != nil { + t.Fatalf("man.cachePut: %v", err) + } + + // The RSA cached cert should be silently ignored and replaced. + cert, err := man.GetCertificate(clientHelloInfo(exampleDomain, true)) + if err != nil { + t.Error(err) + } + if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok { + t.Error("an ECDSA client was served a non-ECDSA certificate") + } + if numCerts := cache.numCerts(); numCerts != 1 { + t.Errorf("found %d certificates in cache; want %d", numCerts, 1) + } +} + +func getCertificateFromManager(man *Manager, ecdsaSupport bool) func(string) error { + return func(sni string) error { + _, err := man.GetCertificate(clientHelloInfo(sni, ecdsaSupport)) + return err + } +} + // startACMEServerStub runs an ACME server // The domain argument is the expected domain name of a certificate request. -func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, finish func()) { +// TODO: Drop this in favour of x/crypto/acme/autocert/internal/acmetest. +func startACMEServerStub(t *testing.T, getCertificate func(string) error, domain string) (url string, finish func()) { // echo token-02 | shasum -a 256 // then divide result in 2 parts separated by dot tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid" verifyTokenCert := func() { - hello := &tls.ClientHelloInfo{ServerName: tokenCertName} - _, err := man.GetCertificate(hello) - if err != nil { + if err := getCertificate(tokenCertName); err != nil { t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err) return } @@ -362,8 +530,7 @@ func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, tick := time.NewTicker(100 * time.Millisecond) defer tick.Stop() for { - hello := &tls.ClientHelloInfo{ServerName: tokenCertName} - if _, err := man.GetCertificate(hello); err != nil { + if err := getCertificate(tokenCertName); err != nil { return } select { @@ -387,21 +554,13 @@ func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, // tests man.GetCertificate flow using the provided hello argument. // The domain argument is the expected domain name of a certificate request. func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) { - url, finish := startACMEServerStub(t, man, domain) + url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), domain) defer finish() - - // use EC key to run faster on 386 - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } - man.Client = &acme.Client{ - Key: key, - DirectoryURL: url, - } + man.Client = &acme.Client{DirectoryURL: url} // simulate tls.Config.GetCertificate var tlscert *tls.Certificate + var err error done := make(chan struct{}) go func() { tlscert, err = man.GetCertificate(hello) @@ -445,13 +604,13 @@ func TestVerifyHTTP01(t *testing.T) { if w.Code != http.StatusOK { t.Errorf("http token: w.Code = %d; want %d", w.Code, http.StatusOK) } - if v := string(w.Body.Bytes()); !strings.HasPrefix(v, "token-http-01.") { + if v := w.Body.String(); !strings.HasPrefix(v, "token-http-01.") { t.Errorf("http token value = %q; want 'token-http-01.' prefix", v) } } // ACME CA server stub, only the needed bits. - // TODO: Merge this with startACMEServerStub, making it a configurable CA for testing. + // TODO: Replace this with x/crypto/acme/autocert/internal/acmetest. var ca *httptest.Server ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Replay-Nonce", "nonce") @@ -505,18 +664,18 @@ func TestVerifyHTTP01(t *testing.T) { })) defer ca.Close() - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } m := &Manager{ Client: &acme.Client{ - Key: key, DirectoryURL: ca.URL, }, } http01 = m.HTTPHandler(nil) - if err := m.verify(context.Background(), m.Client, "example.org"); err != nil { + ctx := context.Background() + client, err := m.acmeClient(ctx) + if err != nil { + t.Fatalf("m.acmeClient: %v", err) + } + if err := m.verify(ctx, client, "example.org"); err != nil { t.Errorf("m.verify: %v", err) } // Only tls-sni-01, tls-sni-02 and http-01 must be accepted @@ -529,6 +688,111 @@ func TestVerifyHTTP01(t *testing.T) { } } +func TestRevokeFailedAuthz(t *testing.T) { + // Prefill authorization URIs expected to be revoked. + // The challenges are selected in a specific order, + // each tried within a newly created authorization. + // This means each authorization URI corresponds to a different challenge type. + revokedAuthz := map[string]bool{ + "/authz/0": false, // tls-sni-02 + "/authz/1": false, // tls-sni-01 + "/authz/2": false, // no viable challenge, but authz is created + } + + var authzCount int // num. of created authorizations + var revokeCount int // num. of revoked authorizations + done := make(chan struct{}) // closed when revokeCount is 3 + + // ACME CA server stub, only the needed bits. + // TODO: Replace this with x/crypto/acme/autocert/internal/acmetest. + var ca *httptest.Server + ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Replay-Nonce", "nonce") + if r.Method == "HEAD" { + // a nonce request + return + } + + switch r.URL.Path { + // Discovery. + case "/": + if err := discoTmpl.Execute(w, ca.URL); err != nil { + t.Errorf("discoTmpl: %v", err) + } + // Client key registration. + case "/new-reg": + w.Write([]byte("{}")) + // New domain authorization. + case "/new-authz": + w.Header().Set("Location", fmt.Sprintf("%s/authz/%d", ca.URL, authzCount)) + w.WriteHeader(http.StatusCreated) + if err := authzTmpl.Execute(w, ca.URL); err != nil { + t.Errorf("authzTmpl: %v", err) + } + authzCount++ + // tls-sni-02 challenge "accept" request. + case "/challenge/2": + // Refuse. + http.Error(w, "won't accept tls-sni-02 challenge", http.StatusBadRequest) + // tls-sni-01 challenge "accept" request. + case "/challenge/1": + // Accept but the authorization will be "expired". + w.Write([]byte("{}")) + // Authorization requests. + case "/authz/0", "/authz/1", "/authz/2": + // Revocation requests. + if r.Method == "POST" { + var req struct{ Status string } + if err := decodePayload(&req, r.Body); err != nil { + t.Errorf("%s: decodePayload: %v", r.URL, err) + } + switch req.Status { + case "deactivated": + revokedAuthz[r.URL.Path] = true + revokeCount++ + if revokeCount >= 3 { + // Last authorization is revoked. + defer close(done) + } + default: + t.Errorf("%s: req.Status = %q; want 'deactivated'", r.URL, req.Status) + } + w.Write([]byte(`{"status": "invalid"}`)) + return + } + // Authorization status requests. + // Simulate abandoned authorization, deleted by the CA. + w.WriteHeader(http.StatusNotFound) + default: + http.NotFound(w, r) + t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path) + } + })) + defer ca.Close() + + m := &Manager{ + Client: &acme.Client{DirectoryURL: ca.URL}, + } + // Should fail and revoke 3 authorizations. + // The first 2 are tsl-sni-02 and tls-sni-01 challenges. + // The third time an authorization is created but no viable challenge is found. + // See revokedAuthz above for more explanation. + if _, err := m.createCert(context.Background(), exampleCertKey); err == nil { + t.Errorf("m.createCert returned nil error") + } + select { + case <-time.After(3 * time.Second): + t.Error("revocations took too long") + case <-done: + // revokeCount is at least 3. + } + for uri, ok := range revokedAuthz { + if !ok { + t.Errorf("%q authorization was not revoked", uri) + } + } +} + func TestHTTPHandlerDefaultFallback(t *testing.T) { tt := []struct { method, url string @@ -571,7 +835,7 @@ func TestHTTPHandlerDefaultFallback(t *testing.T) { } func TestAccountKeyCache(t *testing.T) { - m := Manager{Cache: newMemCache()} + m := Manager{Cache: newMemCache(t)} ctx := context.Background() k1, err := m.accountKey(ctx) if err != nil { @@ -587,36 +851,57 @@ func TestAccountKeyCache(t *testing.T) { } func TestCache(t *testing.T) { - privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + ecdsaKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } - tmpl := &x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{CommonName: "example.org"}, - NotAfter: time.Now().Add(time.Hour), - } - pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &privKey.PublicKey, privKey) + cert, err := dummyCert(ecdsaKey.Public(), exampleDomain) if err != nil { t.Fatal(err) } - tlscert := &tls.Certificate{ - Certificate: [][]byte{pub}, - PrivateKey: privKey, + ecdsaCert := &tls.Certificate{ + Certificate: [][]byte{cert}, + PrivateKey: ecdsaKey, } - man := &Manager{Cache: newMemCache()} + rsaKey, err := rsa.GenerateKey(rand.Reader, 512) + if err != nil { + t.Fatal(err) + } + cert, err = dummyCert(rsaKey.Public(), exampleDomain) + if err != nil { + t.Fatal(err) + } + rsaCert := &tls.Certificate{ + Certificate: [][]byte{cert}, + PrivateKey: rsaKey, + } + + man := &Manager{Cache: newMemCache(t)} defer man.stopRenew() ctx := context.Background() - if err := man.cachePut(ctx, "example.org", tlscert); err != nil { + + if err := man.cachePut(ctx, exampleCertKey, ecdsaCert); err != nil { t.Fatalf("man.cachePut: %v", err) } - res, err := man.cacheGet(ctx, "example.org") + 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 { - t.Fatal("res is nil") + 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) + } + if res == nil || !bytes.Equal(res.Certificate[0], rsaCert.Certificate[0]) { + t.Errorf("man.cacheGet = %+v; want %+v", res, rsaCert) } } @@ -680,26 +965,28 @@ func TestValidCert(t *testing.T) { } tt := []struct { - domain string - key crypto.Signer - cert [][]byte - ok bool + ck certKey + key crypto.Signer + cert [][]byte + ok bool }{ - {"example.org", key1, [][]byte{cert1}, true}, - {"example.org", key3, [][]byte{cert3}, true}, - {"example.org", key1, [][]byte{cert1, cert2, cert3}, true}, - {"example.org", key1, [][]byte{cert1, {1}}, false}, - {"example.org", key1, [][]byte{{1}}, false}, - {"example.org", key1, [][]byte{cert2}, false}, - {"example.org", key2, [][]byte{cert1}, false}, - {"example.org", key1, [][]byte{cert3}, false}, - {"example.org", key3, [][]byte{cert1}, false}, - {"example.net", key1, [][]byte{cert1}, false}, - {"example.org", key1, [][]byte{early}, false}, - {"example.org", key1, [][]byte{expired}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{cert1}, true}, + {certKey{domain: "example.org", isRSA: true}, key3, [][]byte{cert3}, true}, + {certKey{domain: "example.org"}, key1, [][]byte{cert1, cert2, cert3}, true}, + {certKey{domain: "example.org"}, key1, [][]byte{cert1, {1}}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{{1}}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{cert2}, false}, + {certKey{domain: "example.org"}, key2, [][]byte{cert1}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{cert3}, false}, + {certKey{domain: "example.org"}, key3, [][]byte{cert1}, false}, + {certKey{domain: "example.net"}, key1, [][]byte{cert1}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{early}, false}, + {certKey{domain: "example.org"}, key1, [][]byte{expired}, false}, + {certKey{domain: "example.org", isRSA: true}, key1, [][]byte{cert1}, false}, + {certKey{domain: "example.org"}, key3, [][]byte{cert3}, false}, } for i, test := range tt { - leaf, err := validCert(test.domain, test.cert, test.key) + leaf, err := validCert(test.ck, test.cert, test.key, now) if err != nil && test.ok { t.Errorf("%d: err = %v", i, err) } @@ -748,10 +1035,155 @@ func TestManagerGetCertificateBogusSNI(t *testing.T) { {"fo.o", "cache.Get of fo.o"}, } for _, tt := range tests { - _, err := m.GetCertificate(&tls.ClientHelloInfo{ServerName: tt.name}) + _, err := m.GetCertificate(clientHelloInfo(tt.name, true)) got := fmt.Sprint(err) if got != tt.wantErr { t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr) } } } + +func TestCertRequest(t *testing.T) { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + // An extension from RFC7633. Any will do. + ext := pkix.Extension{ + Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1}, + Value: []byte("dummy"), + } + b, err := certRequest(key, "example.org", []pkix.Extension{ext}, "san.example.org") + if err != nil { + t.Fatalf("certRequest: %v", err) + } + r, err := x509.ParseCertificateRequest(b) + if err != nil { + t.Fatalf("ParseCertificateRequest: %v", err) + } + var found bool + for _, v := range r.Extensions { + if v.Id.Equal(ext.Id) { + found = true + break + } + } + if !found { + t.Errorf("want %v in Extensions: %v", ext, r.Extensions) + } +} + +func TestSupportsECDSA(t *testing.T) { + tests := []struct { + CipherSuites []uint16 + SignatureSchemes []tls.SignatureScheme + SupportedCurves []tls.CurveID + ecdsaOk bool + }{ + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, nil, nil, false}, + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, nil, nil, true}, + + // SignatureSchemes limits, not extends, CipherSuites + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256, + }, nil, false}, + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, + }, nil, false}, + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256, + }, nil, true}, + + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256, + }, []tls.CurveID{ + tls.CurveP521, + }, false}, + {[]uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, []tls.SignatureScheme{ + tls.PKCS1WithSHA256, tls.ECDSAWithP256AndSHA256, + }, []tls.CurveID{ + tls.CurveP256, + tls.CurveP521, + }, true}, + } + for i, tt := range tests { + result := supportsECDSA(&tls.ClientHelloInfo{ + CipherSuites: tt.CipherSuites, + SignatureSchemes: tt.SignatureSchemes, + SupportedCurves: tt.SupportedCurves, + }) + if result != tt.ecdsaOk { + t.Errorf("%d: supportsECDSA = %v; want %v", i, result, tt.ecdsaOk) + } + } +} + +// TODO: add same end-to-end for http-01 challenge type. +func TestEndToEnd(t *testing.T) { + const domain = "example.org" + + // ACME CA server + ca := acmetest.NewCAServer([]string{"tls-alpn-01"}, []string{domain}) + defer ca.Close() + + // User dummy server. + m := &Manager{ + Prompt: AcceptTOS, + Client: &acme.Client{DirectoryURL: ca.URL}, + } + us := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("OK")) + })) + us.TLS = &tls.Config{ + NextProtos: []string{"http/1.1", acme.ALPNProto}, + GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { + cert, err := m.GetCertificate(hello) + if err != nil { + t.Errorf("m.GetCertificate: %v", err) + } + return cert, err + }, + } + us.StartTLS() + defer us.Close() + // In TLS-ALPN challenge verification, CA connects to the domain:443 in question. + // Because the domain won't resolve in tests, we need to tell the CA + // where to dial to instead. + ca.Resolve(domain, strings.TrimPrefix(us.URL, "https://")) + + // A client visiting user dummy server. + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: ca.Roots, + ServerName: domain, + }, + } + client := &http.Client{Transport: tr} + res, err := client.Get(us.URL) + if err != nil { + t.Logf("CA errors: %v", ca.Errors()) + t.Fatal(err) + } + defer res.Body.Close() + b, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatal(err) + } + if v := string(b); v != "OK" { + t.Errorf("user server response: %q; want 'OK'", v) + } +} diff --git a/vendor/golang.org/x/crypto/acme/autocert/cache.go b/vendor/golang.org/x/crypto/acme/autocert/cache.go index 61a5fd23..aa9aa845 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/cache.go +++ b/vendor/golang.org/x/crypto/acme/autocert/cache.go @@ -16,10 +16,10 @@ import ( var ErrCacheMiss = errors.New("acme/autocert: certificate cache miss") // Cache is used by Manager to store and retrieve previously obtained certificates -// as opaque data. +// and other account data as opaque blobs. // -// The key argument of the methods refers to a domain name but need not be an FQDN. -// Cache implementations should not rely on the key naming pattern. +// Cache implementations should not rely on the key naming pattern. Keys can +// include any printable ASCII characters, except the following: \/:*?"<>| type Cache interface { // Get returns a certificate data for the specified key. // If there's no such key, Get returns ErrCacheMiss. diff --git a/vendor/golang.org/x/crypto/acme/autocert/example_test.go b/vendor/golang.org/x/crypto/acme/autocert/example_test.go index 552a6254..d4225e5c 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/example_test.go +++ b/vendor/golang.org/x/crypto/acme/autocert/example_test.go @@ -5,7 +5,6 @@ package autocert_test import ( - "crypto/tls" "fmt" "log" "net/http" @@ -25,12 +24,11 @@ func ExampleManager() { m := &autocert.Manager{ Cache: autocert.DirCache("secret-dir"), Prompt: autocert.AcceptTOS, - HostPolicy: autocert.HostWhitelist("example.org"), + HostPolicy: autocert.HostWhitelist("example.org", "www.example.org"), } - go http.ListenAndServe(":http", m.HTTPHandler(nil)) s := &http.Server{ Addr: ":https", - TLSConfig: &tls.Config{GetCertificate: m.GetCertificate}, + TLSConfig: m.TLSConfig(), } s.ListenAndServeTLS("", "") } diff --git a/vendor/golang.org/x/crypto/acme/autocert/internal/acmetest/ca.go b/vendor/golang.org/x/crypto/acme/autocert/internal/acmetest/ca.go new file mode 100644 index 00000000..acc486af --- /dev/null +++ b/vendor/golang.org/x/crypto/acme/autocert/internal/acmetest/ca.go @@ -0,0 +1,416 @@ +// 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 acmetest provides types for testing acme and autocert packages. +// +// TODO: Consider moving this to x/crypto/acme/internal/acmetest for acme tests as well. +package acmetest + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "math/big" + "net/http" + "net/http/httptest" + "sort" + "strings" + "sync" + "time" +) + +// CAServer is a simple test server which implements ACME spec bits needed for testing. +type CAServer struct { + URL string // server URL after it has been started + Roots *x509.CertPool // CA root certificates; initialized in NewCAServer + + rootKey crypto.Signer + rootCert []byte // DER encoding + rootTemplate *x509.Certificate + + server *httptest.Server + challengeTypes []string // supported challenge types + domainsWhitelist []string // only these domains are valid for issuing, unless empty + + mu sync.Mutex + certCount int // number of issued certs + domainAddr map[string]string // domain name to addr:port resolution + authorizations map[string]*authorization // keyed by domain name + errors []error // encountered client errors +} + +// NewCAServer creates a new ACME test server and starts serving requests. +// The returned CAServer issues certs signed with the CA roots +// available in the Roots field. +// +// The challengeTypes argument defines the supported ACME challenge types +// sent to a client in a response for a domain authorization. +// If domainsWhitelist is non-empty, the certs will be issued only for the specified +// list of domains. Otherwise, any domain name is allowed. +func NewCAServer(challengeTypes []string, domainsWhitelist []string) *CAServer { + var whitelist []string + for _, name := range domainsWhitelist { + whitelist = append(whitelist, name) + } + sort.Strings(whitelist) + ca := &CAServer{ + challengeTypes: challengeTypes, + domainsWhitelist: whitelist, + domainAddr: make(map[string]string), + authorizations: make(map[string]*authorization), + } + + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic(fmt.Sprintf("ecdsa.GenerateKey: %v", err)) + } + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Test Acme Co"}, + CommonName: "Root CA", + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(365 * 24 * time.Hour), + KeyUsage: x509.KeyUsageCertSign, + BasicConstraintsValid: true, + IsCA: true, + } + der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key) + if err != nil { + panic(fmt.Sprintf("x509.CreateCertificate: %v", err)) + } + cert, err := x509.ParseCertificate(der) + if err != nil { + panic(fmt.Sprintf("x509.ParseCertificate: %v", err)) + } + ca.Roots = x509.NewCertPool() + ca.Roots.AddCert(cert) + ca.rootKey = key + ca.rootCert = der + ca.rootTemplate = tmpl + + ca.server = httptest.NewServer(http.HandlerFunc(ca.handle)) + ca.URL = ca.server.URL + return ca +} + +// Close shuts down the server and blocks until all outstanding +// requests on this server have completed. +func (ca *CAServer) Close() { + ca.server.Close() +} + +// Errors returns all client errors. +func (ca *CAServer) Errors() []error { + ca.mu.Lock() + defer ca.mu.Unlock() + return ca.errors +} + +// Resolve adds a domain to address resolution for the ca to dial to +// when validating challenges for the domain authorization. +func (ca *CAServer) Resolve(domain, addr string) { + ca.mu.Lock() + defer ca.mu.Unlock() + ca.domainAddr[domain] = addr +} + +type discovery struct { + NewReg string `json:"new-reg"` + NewAuthz string `json:"new-authz"` + NewCert string `json:"new-cert"` +} + +type challenge struct { + URI string `json:"uri"` + Type string `json:"type"` + Token string `json:"token"` +} + +type authorization struct { + Status string `json:"status"` + Challenges []challenge `json:"challenges"` + + id int + domain string +} + +func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Replay-Nonce", "nonce") + if r.Method == "HEAD" { + // a nonce request + return + } + + // TODO: Verify nonce header for all POST requests. + + switch { + default: + err := fmt.Errorf("unrecognized r.URL.Path: %s", r.URL.Path) + ca.addError(err) + http.Error(w, err.Error(), http.StatusBadRequest) + + // Discovery request. + case r.URL.Path == "/": + resp := &discovery{ + NewReg: ca.serverURL("/new-reg"), + NewAuthz: ca.serverURL("/new-authz"), + NewCert: ca.serverURL("/new-cert"), + } + if err := json.NewEncoder(w).Encode(resp); err != nil { + panic(fmt.Sprintf("discovery response: %v", err)) + } + + // Client key registration request. + case r.URL.Path == "/new-reg": + // TODO: Check the user account key against a ca.accountKeys? + w.Write([]byte("{}")) + + // Domain authorization request. + case r.URL.Path == "/new-authz": + var req struct { + Identifier struct{ Value string } + } + if err := decodePayload(&req, r.Body); err != nil { + ca.addError(err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + ca.mu.Lock() + defer ca.mu.Unlock() + authz, ok := ca.authorizations[req.Identifier.Value] + if !ok { + authz = &authorization{ + domain: req.Identifier.Value, + Status: "pending", + } + for _, typ := range ca.challengeTypes { + authz.Challenges = append(authz.Challenges, challenge{ + Type: typ, + URI: ca.serverURL("/challenge/%s/%s", typ, authz.domain), + Token: challengeToken(authz.domain, typ), + }) + } + ca.authorizations[authz.domain] = authz + } + w.Header().Set("Location", ca.serverURL("/authz/%s", authz.domain)) + w.WriteHeader(http.StatusCreated) + if err := json.NewEncoder(w).Encode(authz); err != nil { + panic(fmt.Sprintf("new authz response: %v", err)) + } + + // Accept tls-alpn-01 challenge type requests. + // TODO: Add http-01 and dns-01 handlers. + case strings.HasPrefix(r.URL.Path, "/challenge/tls-alpn-01/"): + domain := strings.TrimPrefix(r.URL.Path, "/challenge/tls-alpn-01/") + ca.mu.Lock() + defer ca.mu.Unlock() + if _, ok := ca.authorizations[domain]; !ok { + err := fmt.Errorf("challenge accept: no authz for %q", domain) + ca.addError(err) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + go func(domain string) { + err := ca.verifyALPNChallenge(domain) + ca.mu.Lock() + defer ca.mu.Unlock() + authz := ca.authorizations[domain] + if err != nil { + authz.Status = "invalid" + return + } + authz.Status = "valid" + + }(domain) + w.Write([]byte("{}")) + + // Get authorization status requests. + case strings.HasPrefix(r.URL.Path, "/authz/"): + domain := strings.TrimPrefix(r.URL.Path, "/authz/") + ca.mu.Lock() + defer ca.mu.Unlock() + authz, ok := ca.authorizations[domain] + if !ok { + http.Error(w, fmt.Sprintf("no authz for %q", domain), http.StatusNotFound) + return + } + if err := json.NewEncoder(w).Encode(authz); err != nil { + panic(fmt.Sprintf("get authz for %q response: %v", domain, err)) + } + + // Cert issuance request. + case r.URL.Path == "/new-cert": + var req struct { + CSR string `json:"csr"` + } + decodePayload(&req, r.Body) + b, _ := base64.RawURLEncoding.DecodeString(req.CSR) + csr, err := x509.ParseCertificateRequest(b) + if err != nil { + ca.addError(err) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + names := unique(append(csr.DNSNames, csr.Subject.CommonName)) + if err := ca.matchWhitelist(names); err != nil { + ca.addError(err) + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + if err := ca.authorized(names); err != nil { + ca.addError(err) + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + der, err := ca.leafCert(csr) + if err != nil { + err = fmt.Errorf("new-cert response: ca.leafCert: %v", err) + ca.addError(err) + http.Error(w, err.Error(), http.StatusBadRequest) + } + w.Header().Set("Link", fmt.Sprintf("<%s>; rel=up", ca.serverURL("/ca-cert"))) + w.WriteHeader(http.StatusCreated) + w.Write(der) + + // CA chain cert request. + case r.URL.Path == "/ca-cert": + w.Write(ca.rootCert) + } +} + +func (ca *CAServer) addError(err error) { + ca.mu.Lock() + defer ca.mu.Unlock() + ca.errors = append(ca.errors, err) +} + +func (ca *CAServer) serverURL(format string, arg ...interface{}) string { + return ca.server.URL + fmt.Sprintf(format, arg...) +} + +func (ca *CAServer) matchWhitelist(dnsNames []string) error { + if len(ca.domainsWhitelist) == 0 { + return nil + } + var nomatch []string + for _, name := range dnsNames { + i := sort.SearchStrings(ca.domainsWhitelist, name) + if i == len(ca.domainsWhitelist) || ca.domainsWhitelist[i] != name { + nomatch = append(nomatch, name) + } + } + if len(nomatch) > 0 { + return fmt.Errorf("matchWhitelist: some domains don't match: %q", nomatch) + } + return nil +} + +func (ca *CAServer) authorized(dnsNames []string) error { + ca.mu.Lock() + defer ca.mu.Unlock() + var noauthz []string + for _, name := range dnsNames { + authz, ok := ca.authorizations[name] + if !ok || authz.Status != "valid" { + noauthz = append(noauthz, name) + } + } + if len(noauthz) > 0 { + return fmt.Errorf("CAServer: no authz for %q", noauthz) + } + return nil +} + +func (ca *CAServer) leafCert(csr *x509.CertificateRequest) (der []byte, err error) { + ca.mu.Lock() + defer ca.mu.Unlock() + ca.certCount++ // next leaf cert serial number + leaf := &x509.Certificate{ + SerialNumber: big.NewInt(int64(ca.certCount)), + Subject: pkix.Name{Organization: []string{"Test Acme Co"}}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(90 * 24 * time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + DNSNames: csr.DNSNames, + BasicConstraintsValid: true, + } + if len(csr.DNSNames) == 0 { + leaf.DNSNames = []string{csr.Subject.CommonName} + } + return x509.CreateCertificate(rand.Reader, leaf, ca.rootTemplate, csr.PublicKey, ca.rootKey) +} + +func (ca *CAServer) addr(domain string) (string, error) { + ca.mu.Lock() + defer ca.mu.Unlock() + addr, ok := ca.domainAddr[domain] + if !ok { + return "", fmt.Errorf("CAServer: no addr resolution for %q", domain) + } + return addr, nil +} + +func (ca *CAServer) verifyALPNChallenge(domain string) error { + const acmeALPNProto = "acme-tls/1" + + addr, err := ca.addr(domain) + if err != nil { + return err + } + conn, err := tls.Dial("tcp", addr, &tls.Config{ + ServerName: domain, + InsecureSkipVerify: true, + NextProtos: []string{acmeALPNProto}, + }) + if err != nil { + return err + } + if v := conn.ConnectionState().NegotiatedProtocol; v != acmeALPNProto { + return fmt.Errorf("CAServer: verifyALPNChallenge: negotiated proto is %q; want %q", v, acmeALPNProto) + } + if n := len(conn.ConnectionState().PeerCertificates); n != 1 { + return fmt.Errorf("len(PeerCertificates) = %d; want 1", n) + } + // TODO: verify conn.ConnectionState().PeerCertificates[0] + return nil +} + +func decodePayload(v interface{}, r io.Reader) error { + var req struct{ Payload string } + if err := json.NewDecoder(r).Decode(&req); err != nil { + return err + } + payload, err := base64.RawURLEncoding.DecodeString(req.Payload) + if err != nil { + return err + } + return json.Unmarshal(payload, v) +} + +func challengeToken(domain, challType string) string { + return fmt.Sprintf("token-%s-%s", domain, challType) +} + +func unique(a []string) []string { + seen := make(map[string]bool) + var res []string + for _, s := range a { + if s != "" && !seen[s] { + seen[s] = true + res = append(res, s) + } + } + return res +} diff --git a/vendor/golang.org/x/crypto/acme/autocert/listener.go b/vendor/golang.org/x/crypto/acme/autocert/listener.go index d744df0e..1e069818 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/listener.go +++ b/vendor/golang.org/x/crypto/acme/autocert/listener.go @@ -72,11 +72,8 @@ func NewListener(domains ...string) net.Listener { // the Manager m's Prompt, Cache, HostPolicy, and other desired options. func (m *Manager) Listener() net.Listener { ln := &listener{ - m: m, - conf: &tls.Config{ - GetCertificate: m.GetCertificate, // bonus: panic on nil m - NextProtos: []string{"h2", "http/1.1"}, // Enable HTTP/2 - }, + m: m, + conf: m.TLSConfig(), } ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443") return ln diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal.go b/vendor/golang.org/x/crypto/acme/autocert/renewal.go index 6c5da2bc..665f870d 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/renewal.go +++ b/vendor/golang.org/x/crypto/acme/autocert/renewal.go @@ -17,9 +17,9 @@ const renewJitter = time.Hour // domainRenewal tracks the state used by the periodic timers // renewing a single domain's cert. type domainRenewal struct { - m *Manager - domain string - key crypto.Signer + m *Manager + ck certKey + key crypto.Signer timerMu sync.Mutex timer *time.Timer @@ -71,25 +71,43 @@ func (dr *domainRenewal) renew() { testDidRenewLoop(next, err) } +// updateState locks and replaces the relevant Manager.state item with the given +// state. It additionally updates dr.key with the given state's key. +func (dr *domainRenewal) updateState(state *certState) { + dr.m.stateMu.Lock() + defer dr.m.stateMu.Unlock() + dr.key = state.key + dr.m.state[dr.ck] = state +} + // do is similar to Manager.createCert but it doesn't lock a Manager.state item. // Instead, it requests a new certificate independently and, upon success, // replaces dr.m.state item with a new one and updates cache for the given domain. // -// It may return immediately if the expiration date of the currently cached cert -// is far enough in the future. +// It may lock and update the Manager.state if the expiration date of the currently +// cached cert is far enough in the future. // // The returned value is a time interval after which the renewal should occur again. func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { // a race is likely unavoidable in a distributed environment // but we try nonetheless - if tlscert, err := dr.m.cacheGet(ctx, dr.domain); err == nil { + if tlscert, err := dr.m.cacheGet(ctx, dr.ck); err == nil { next := dr.next(tlscert.Leaf.NotAfter) if next > dr.m.renewBefore()+renewJitter { - return next, nil + signer, ok := tlscert.PrivateKey.(crypto.Signer) + if ok { + state := &certState{ + key: signer, + cert: tlscert.Certificate, + leaf: tlscert.Leaf, + } + dr.updateState(state) + return next, nil + } } } - der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.domain) + der, leaf, err := dr.m.authorizedCert(ctx, dr.key, dr.ck) if err != nil { return 0, err } @@ -102,16 +120,15 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) { if err != nil { return 0, err } - dr.m.cachePut(ctx, dr.domain, tlscert) - dr.m.stateMu.Lock() - defer dr.m.stateMu.Unlock() - // m.state is guaranteed to be non-nil at this point - dr.m.state[dr.domain] = state + if err := dr.m.cachePut(ctx, dr.ck, tlscert); err != nil { + return 0, err + } + dr.updateState(state) return dr.next(leaf.NotAfter), nil } func (dr *domainRenewal) next(expiry time.Time) time.Duration { - d := expiry.Sub(timeNow()) - dr.m.renewBefore() + d := expiry.Sub(dr.m.now()) - dr.m.renewBefore() // add a bit of randomness to renew deadline n := pseudoRand.int63n(int64(renewJitter)) d -= time.Duration(n) diff --git a/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go b/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go index 11d40ff5..5d1c63ff 100644 --- a/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go +++ b/vendor/golang.org/x/crypto/acme/autocert/renewal_test.go @@ -23,10 +23,10 @@ import ( func TestRenewalNext(t *testing.T) { now := time.Now() - timeNow = func() time.Time { return now } - defer func() { timeNow = time.Now }() - - man := &Manager{RenewBefore: 7 * 24 * time.Hour} + man := &Manager{ + RenewBefore: 7 * 24 * time.Hour, + nowFunc: func() time.Time { return now }, + } defer man.stopRenew() tt := []struct { expiry time.Time @@ -48,8 +48,6 @@ func TestRenewalNext(t *testing.T) { } func TestRenewFromCache(t *testing.T) { - const domain = "example.org" - // ACME CA server stub var ca *httptest.Server ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -84,7 +82,7 @@ func TestRenewFromCache(t *testing.T) { if err != nil { t.Fatalf("new-cert: CSR: %v", err) } - der, err := dummyCert(csr.PublicKey, domain) + der, err := dummyCert(csr.PublicKey, exampleDomain) if err != nil { t.Fatalf("new-cert: dummyCert: %v", err) } @@ -105,30 +103,28 @@ func TestRenewFromCache(t *testing.T) { })) defer ca.Close() - // use EC key to run faster on 386 - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - t.Fatal(err) - } man := &Manager{ Prompt: AcceptTOS, - Cache: newMemCache(), + Cache: newMemCache(t), RenewBefore: 24 * time.Hour, Client: &acme.Client{ - Key: key, DirectoryURL: ca.URL, }, } defer man.stopRenew() // cache an almost expired cert + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } now := time.Now() - cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), domain) + cert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain) if err != nil { t.Fatal(err) } tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}} - if err := man.cachePut(context.Background(), domain, tlscert); err != nil { + if err := man.cachePut(context.Background(), exampleCertKey, tlscert); err != nil { t.Fatal(err) } @@ -152,7 +148,7 @@ func TestRenewFromCache(t *testing.T) { // ensure the new cert is cached after := time.Now().Add(future) - tlscert, err := man.cacheGet(context.Background(), domain) + tlscert, err := man.cacheGet(context.Background(), exampleCertKey) if err != nil { t.Fatalf("man.cacheGet: %v", err) } @@ -163,9 +159,9 @@ func TestRenewFromCache(t *testing.T) { // verify the old cert is also replaced in memory man.stateMu.Lock() defer man.stateMu.Unlock() - s := man.state[domain] + s := man.state[exampleCertKey] if s == nil { - t.Fatalf("m.state[%q] is nil", domain) + t.Fatalf("m.state[%q] is nil", exampleCertKey) } tlscert, err = s.tlscert() if err != nil { @@ -177,7 +173,7 @@ func TestRenewFromCache(t *testing.T) { } // trigger renew - hello := &tls.ClientHelloInfo{ServerName: domain} + hello := clientHelloInfo(exampleDomain, true) if _, err := man.GetCertificate(hello); err != nil { t.Fatal(err) } @@ -189,3 +185,145 @@ func TestRenewFromCache(t *testing.T) { case <-done: } } + +func TestRenewFromCacheAlreadyRenewed(t *testing.T) { + man := &Manager{ + Prompt: AcceptTOS, + Cache: newMemCache(t), + RenewBefore: 24 * time.Hour, + Client: &acme.Client{ + DirectoryURL: "invalid", + }, + } + defer man.stopRenew() + + // cache a recently renewed cert with a different private key + newKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + now := time.Now() + newCert, err := dateDummyCert(newKey.Public(), now.Add(-2*time.Hour), now.Add(time.Hour*24*90), exampleDomain) + if err != nil { + t.Fatal(err) + } + newLeaf, err := validCert(exampleCertKey, [][]byte{newCert}, newKey, now) + if err != nil { + t.Fatal(err) + } + newTLSCert := &tls.Certificate{PrivateKey: newKey, Certificate: [][]byte{newCert}, Leaf: newLeaf} + if err := man.cachePut(context.Background(), exampleCertKey, newTLSCert); err != nil { + t.Fatal(err) + } + + // set internal state to an almost expired cert + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + oldCert, err := dateDummyCert(key.Public(), now.Add(-2*time.Hour), now.Add(time.Minute), exampleDomain) + if err != nil { + t.Fatal(err) + } + oldLeaf, err := validCert(exampleCertKey, [][]byte{oldCert}, key, now) + if err != nil { + t.Fatal(err) + } + man.stateMu.Lock() + if man.state == nil { + man.state = make(map[certKey]*certState) + } + s := &certState{ + key: key, + cert: [][]byte{oldCert}, + leaf: oldLeaf, + } + man.state[exampleCertKey] = s + man.stateMu.Unlock() + + // veriy the renewal accepted the newer cached cert + defer func() { + testDidRenewLoop = func(next time.Duration, err error) {} + }() + done := make(chan struct{}) + testDidRenewLoop = func(next time.Duration, err error) { + defer close(done) + if err != nil { + t.Errorf("testDidRenewLoop: %v", err) + } + // Next should be about 90 days + // Previous expiration was within 1 min. + future := 88 * 24 * time.Hour + if next < future { + t.Errorf("testDidRenewLoop: next = %v; want >= %v", next, future) + } + + // ensure the cached cert was not modified + tlscert, err := man.cacheGet(context.Background(), exampleCertKey) + if err != nil { + t.Fatalf("man.cacheGet: %v", err) + } + if !tlscert.Leaf.NotAfter.Equal(newLeaf.NotAfter) { + t.Errorf("cache leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newLeaf.NotAfter) + } + + // verify the old cert is also replaced in memory + man.stateMu.Lock() + defer man.stateMu.Unlock() + s := man.state[exampleCertKey] + if s == nil { + t.Fatalf("m.state[%q] is nil", exampleCertKey) + } + stateKey := s.key.Public().(*ecdsa.PublicKey) + if stateKey.X.Cmp(newKey.X) != 0 || stateKey.Y.Cmp(newKey.Y) != 0 { + t.Fatalf("state key was not updated from cache x: %v y: %v; want x: %v y: %v", stateKey.X, stateKey.Y, newKey.X, newKey.Y) + } + tlscert, err = s.tlscert() + if err != nil { + t.Fatalf("s.tlscert: %v", err) + } + if !tlscert.Leaf.NotAfter.Equal(newLeaf.NotAfter) { + t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newLeaf.NotAfter) + } + + // verify the private key is replaced in the renewal state + r := man.renewal[exampleCertKey] + if r == nil { + t.Fatalf("m.renewal[%q] is nil", exampleCertKey) + } + renewalKey := r.key.Public().(*ecdsa.PublicKey) + if renewalKey.X.Cmp(newKey.X) != 0 || renewalKey.Y.Cmp(newKey.Y) != 0 { + t.Fatalf("renewal private key was not updated from cache x: %v y: %v; want x: %v y: %v", renewalKey.X, renewalKey.Y, newKey.X, newKey.Y) + } + + } + + // assert the expiring cert is returned from state + hello := clientHelloInfo(exampleDomain, true) + tlscert, err := man.GetCertificate(hello) + if err != nil { + t.Fatal(err) + } + if !oldLeaf.NotAfter.Equal(tlscert.Leaf.NotAfter) { + t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, oldLeaf.NotAfter) + } + + // trigger renew + go man.renew(exampleCertKey, s.key, s.leaf.NotAfter) + + // wait for renew loop + select { + case <-time.After(10 * time.Second): + t.Fatal("renew took too long to occur") + case <-done: + // assert the new cert is returned from state after renew + hello := clientHelloInfo(exampleDomain, true) + tlscert, err := man.GetCertificate(hello) + if err != nil { + t.Fatal(err) + } + if !newTLSCert.Leaf.NotAfter.Equal(tlscert.Leaf.NotAfter) { + t.Errorf("state leaf.NotAfter = %v; want == %v", tlscert.Leaf.NotAfter, newTLSCert.Leaf.NotAfter) + } + } +} diff --git a/vendor/golang.org/x/crypto/acme/http.go b/vendor/golang.org/x/crypto/acme/http.go new file mode 100644 index 00000000..a43ce6a5 --- /dev/null +++ b/vendor/golang.org/x/crypto/acme/http.go @@ -0,0 +1,281 @@ +// 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 acme + +import ( + "bytes" + "context" + "crypto" + "crypto/rand" + "encoding/json" + "fmt" + "io/ioutil" + "math/big" + "net/http" + "strconv" + "strings" + "time" +) + +// retryTimer encapsulates common logic for retrying unsuccessful requests. +// It is not safe for concurrent use. +type retryTimer struct { + // backoffFn provides backoff delay sequence for retries. + // See Client.RetryBackoff doc comment. + backoffFn func(n int, r *http.Request, res *http.Response) time.Duration + // n is the current retry attempt. + n int +} + +func (t *retryTimer) inc() { + t.n++ +} + +// backoff pauses the current goroutine as described in Client.RetryBackoff. +func (t *retryTimer) backoff(ctx context.Context, r *http.Request, res *http.Response) error { + d := t.backoffFn(t.n, r, res) + if d <= 0 { + return fmt.Errorf("acme: no more retries for %s; tried %d time(s)", r.URL, t.n) + } + wakeup := time.NewTimer(d) + defer wakeup.Stop() + select { + case <-ctx.Done(): + return ctx.Err() + case <-wakeup.C: + return nil + } +} + +func (c *Client) retryTimer() *retryTimer { + f := c.RetryBackoff + if f == nil { + f = defaultBackoff + } + return &retryTimer{backoffFn: f} +} + +// defaultBackoff provides default Client.RetryBackoff implementation +// using a truncated exponential backoff algorithm, +// as described in Client.RetryBackoff. +// +// The n argument is always bounded between 1 and 30. +// The returned value is always greater than 0. +func defaultBackoff(n int, r *http.Request, res *http.Response) time.Duration { + const max = 10 * time.Second + var jitter time.Duration + if x, err := rand.Int(rand.Reader, big.NewInt(1000)); err == nil { + // Set the minimum to 1ms to avoid a case where + // an invalid Retry-After value is parsed into 0 below, + // resulting in the 0 returned value which would unintentionally + // stop the retries. + jitter = (1 + time.Duration(x.Int64())) * time.Millisecond + } + if v, ok := res.Header["Retry-After"]; ok { + return retryAfter(v[0]) + jitter + } + + if n < 1 { + n = 1 + } + if n > 30 { + n = 30 + } + d := time.Duration(1< max { + return max + } + return d +} + +// retryAfter parses a Retry-After HTTP header value, +// trying to convert v into an int (seconds) or use http.ParseTime otherwise. +// It returns zero value if v cannot be parsed. +func retryAfter(v string) time.Duration { + if i, err := strconv.Atoi(v); err == nil { + return time.Duration(i) * time.Second + } + t, err := http.ParseTime(v) + if err != nil { + return 0 + } + return t.Sub(timeNow()) +} + +// resOkay is a function that reports whether the provided response is okay. +// It is expected to keep the response body unread. +type resOkay func(*http.Response) bool + +// wantStatus returns a function which reports whether the code +// matches the status code of a response. +func wantStatus(codes ...int) resOkay { + return func(res *http.Response) bool { + for _, code := range codes { + if code == res.StatusCode { + return true + } + } + return false + } +} + +// get issues an unsigned GET request to the specified URL. +// It returns a non-error value only when ok reports true. +// +// get retries unsuccessful attempts according to c.RetryBackoff +// until the context is done or a non-retriable error is received. +func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Response, error) { + retry := c.retryTimer() + for { + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + res, err := c.doNoRetry(ctx, req) + switch { + case err != nil: + return nil, err + case ok(res): + return res, nil + case isRetriable(res.StatusCode): + retry.inc() + resErr := responseError(res) + res.Body.Close() + // Ignore the error value from retry.backoff + // and return the one from last retry, as received from the CA. + if retry.backoff(ctx, req, res) != nil { + return nil, resErr + } + default: + defer res.Body.Close() + return nil, responseError(res) + } + } +} + +// post issues a signed POST request in JWS format using the provided key +// to the specified URL. +// It returns a non-error value only when ok reports true. +// +// post retries unsuccessful attempts according to c.RetryBackoff +// until the context is done or a non-retriable error is received. +// It uses postNoRetry to make individual requests. +func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body interface{}, ok resOkay) (*http.Response, error) { + retry := c.retryTimer() + for { + res, req, err := c.postNoRetry(ctx, key, url, body) + if err != nil { + return nil, err + } + if ok(res) { + return res, nil + } + resErr := responseError(res) + res.Body.Close() + switch { + // Check for bad nonce before isRetriable because it may have been returned + // with an unretriable response code such as 400 Bad Request. + case isBadNonce(resErr): + // Consider any previously stored nonce values to be invalid. + c.clearNonces() + case !isRetriable(res.StatusCode): + return nil, resErr + } + retry.inc() + // Ignore the error value from retry.backoff + // and return the one from last retry, as received from the CA. + if err := retry.backoff(ctx, req, res); err != nil { + return nil, resErr + } + } +} + +// postNoRetry signs the body with the given key and POSTs it to the provided url. +// The body argument must be JSON-serializable. +// It is used by c.post to retry unsuccessful attempts. +func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, *http.Request, error) { + nonce, err := c.popNonce(ctx, url) + if err != nil { + return nil, nil, err + } + b, err := jwsEncodeJSON(body, key, nonce) + if err != nil { + return nil, nil, err + } + req, err := http.NewRequest("POST", url, bytes.NewReader(b)) + if err != nil { + return nil, nil, err + } + req.Header.Set("Content-Type", "application/jose+json") + res, err := c.doNoRetry(ctx, req) + if err != nil { + return nil, nil, err + } + c.addNonce(res.Header) + return res, req, nil +} + +// doNoRetry issues a request req, replacing its context (if any) with ctx. +func (c *Client) doNoRetry(ctx context.Context, req *http.Request) (*http.Response, error) { + res, err := c.httpClient().Do(req.WithContext(ctx)) + if err != nil { + select { + case <-ctx.Done(): + // Prefer the unadorned context error. + // (The acme package had tests assuming this, previously from ctxhttp's + // behavior, predating net/http supporting contexts natively) + // TODO(bradfitz): reconsider this in the future. But for now this + // requires no test updates. + return nil, ctx.Err() + default: + return nil, err + } + } + return res, nil +} + +func (c *Client) httpClient() *http.Client { + if c.HTTPClient != nil { + return c.HTTPClient + } + return http.DefaultClient +} + +// isBadNonce reports whether err is an ACME "badnonce" error. +func isBadNonce(err error) bool { + // According to the spec badNonce is urn:ietf:params:acme:error:badNonce. + // However, ACME servers in the wild return their versions of the error. + // See https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4 + // and https://github.com/letsencrypt/boulder/blob/0e07eacb/docs/acme-divergences.md#section-66. + ae, ok := err.(*Error) + return ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") +} + +// isRetriable reports whether a request can be retried +// based on the response status code. +// +// Note that a "bad nonce" error is returned with a non-retriable 400 Bad Request code. +// Callers should parse the response and check with isBadNonce. +func isRetriable(code int) bool { + return code <= 399 || code >= 500 || code == http.StatusTooManyRequests +} + +// responseError creates an error of Error type from resp. +func responseError(resp *http.Response) error { + // don't care if ReadAll returns an error: + // json.Unmarshal will fail in that case anyway + b, _ := ioutil.ReadAll(resp.Body) + e := &wireError{Status: resp.StatusCode} + if err := json.Unmarshal(b, e); err != nil { + // this is not a regular error response: + // populate detail with anything we received, + // e.Status will already contain HTTP response code value + e.Detail = string(b) + if e.Detail == "" { + e.Detail = resp.Status + } + } + return e.error(resp.Header) +} diff --git a/vendor/golang.org/x/crypto/acme/http_test.go b/vendor/golang.org/x/crypto/acme/http_test.go new file mode 100644 index 00000000..15e401ba --- /dev/null +++ b/vendor/golang.org/x/crypto/acme/http_test.go @@ -0,0 +1,209 @@ +// 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 acme + +import ( + "context" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "reflect" + "strings" + "testing" + "time" +) + +func TestDefaultBackoff(t *testing.T) { + tt := []struct { + nretry int + retryAfter string // Retry-After header + out time.Duration // expected min; max = min + jitter + }{ + {-1, "", time.Second}, // verify the lower bound is 1 + {0, "", time.Second}, // verify the lower bound is 1 + {100, "", 10 * time.Second}, // verify the ceiling + {1, "3600", time.Hour}, // verify the header value is used + {1, "", 1 * time.Second}, + {2, "", 2 * time.Second}, + {3, "", 4 * time.Second}, + {4, "", 8 * time.Second}, + } + for i, test := range tt { + r := httptest.NewRequest("GET", "/", nil) + resp := &http.Response{Header: http.Header{}} + if test.retryAfter != "" { + resp.Header.Set("Retry-After", test.retryAfter) + } + d := defaultBackoff(test.nretry, r, resp) + max := test.out + time.Second // + max jitter + if d < test.out || max < d { + t.Errorf("%d: defaultBackoff(%v) = %v; want between %v and %v", i, test.nretry, d, test.out, max) + } + } +} + +func TestErrorResponse(t *testing.T) { + s := `{ + "status": 400, + "type": "urn:acme:error:xxx", + "detail": "text" + }` + res := &http.Response{ + StatusCode: 400, + Status: "400 Bad Request", + Body: ioutil.NopCloser(strings.NewReader(s)), + Header: http.Header{"X-Foo": {"bar"}}, + } + err := responseError(res) + v, ok := err.(*Error) + if !ok { + t.Fatalf("err = %+v (%T); want *Error type", err, err) + } + if v.StatusCode != 400 { + t.Errorf("v.StatusCode = %v; want 400", v.StatusCode) + } + if v.ProblemType != "urn:acme:error:xxx" { + t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType) + } + if v.Detail != "text" { + t.Errorf("v.Detail = %q; want text", v.Detail) + } + if !reflect.DeepEqual(v.Header, res.Header) { + t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header) + } +} + +func TestPostWithRetries(t *testing.T) { + var count int + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + count++ + w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count)) + if r.Method == "HEAD" { + // We expect the client to do 2 head requests to fetch + // nonces, one to start and another after getting badNonce + return + } + + head, err := decodeJWSHead(r) + switch { + case err != nil: + t.Errorf("decodeJWSHead: %v", err) + case head.Nonce == "": + t.Error("head.Nonce is empty") + case head.Nonce == "nonce1": + // Return a badNonce error to force the call to retry. + w.Header().Set("Retry-After", "0") + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`)) + return + } + // Make client.Authorize happy; we're not testing its result. + w.WriteHeader(http.StatusCreated) + w.Write([]byte(`{"status":"valid"}`)) + })) + defer ts.Close() + + client := &Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}} + // This call will fail with badNonce, causing a retry + if _, err := client.Authorize(context.Background(), "example.com"); err != nil { + t.Errorf("client.Authorize 1: %v", err) + } + if count != 4 { + t.Errorf("total requests count: %d; want 4", count) + } +} + +func TestRetryErrorType(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Replay-Nonce", "nonce") + w.WriteHeader(http.StatusTooManyRequests) + w.Write([]byte(`{"type":"rateLimited"}`)) + })) + defer ts.Close() + + client := &Client{ + Key: testKey, + RetryBackoff: func(n int, r *http.Request, res *http.Response) time.Duration { + // Do no retries. + return 0 + }, + dir: &Directory{AuthzURL: ts.URL}, + } + + t.Run("post", func(t *testing.T) { + testRetryErrorType(t, func() error { + _, err := client.Authorize(context.Background(), "example.com") + return err + }) + }) + t.Run("get", func(t *testing.T) { + testRetryErrorType(t, func() error { + _, err := client.GetAuthorization(context.Background(), ts.URL) + return err + }) + }) +} + +func testRetryErrorType(t *testing.T, callClient func() error) { + t.Helper() + err := callClient() + if err == nil { + t.Fatal("client.Authorize returned nil error") + } + acmeErr, ok := err.(*Error) + if !ok { + t.Fatalf("err is %v (%T); want *Error", err, err) + } + if acmeErr.StatusCode != http.StatusTooManyRequests { + t.Errorf("acmeErr.StatusCode = %d; want %d", acmeErr.StatusCode, http.StatusTooManyRequests) + } + if acmeErr.ProblemType != "rateLimited" { + t.Errorf("acmeErr.ProblemType = %q; want 'rateLimited'", acmeErr.ProblemType) + } +} + +func TestRetryBackoffArgs(t *testing.T) { + const resCode = http.StatusInternalServerError + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Replay-Nonce", "test-nonce") + w.WriteHeader(resCode) + })) + defer ts.Close() + + // Canceled in backoff. + ctx, cancel := context.WithCancel(context.Background()) + + var nretry int + backoff := func(n int, r *http.Request, res *http.Response) time.Duration { + nretry++ + if n != nretry { + t.Errorf("n = %d; want %d", n, nretry) + } + if nretry == 3 { + cancel() + } + + if r == nil { + t.Error("r is nil") + } + if res.StatusCode != resCode { + t.Errorf("res.StatusCode = %d; want %d", res.StatusCode, resCode) + } + return time.Millisecond + } + + client := &Client{ + Key: testKey, + RetryBackoff: backoff, + dir: &Directory{AuthzURL: ts.URL}, + } + if _, err := client.Authorize(ctx, "example.com"); err == nil { + t.Error("err is nil") + } + if nretry != 3 { + t.Errorf("nretry = %d; want 3", nretry) + } +} diff --git a/vendor/golang.org/x/crypto/acme/jws.go b/vendor/golang.org/x/crypto/acme/jws.go index 6cbca25d..1093b503 100644 --- a/vendor/golang.org/x/crypto/acme/jws.go +++ b/vendor/golang.org/x/crypto/acme/jws.go @@ -25,7 +25,7 @@ func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byt if err != nil { return nil, err } - alg, sha := jwsHasher(key) + alg, sha := jwsHasher(key.Public()) if alg == "" || !sha.Available() { return nil, ErrUnsupportedKey } @@ -97,13 +97,16 @@ func jwkEncode(pub crypto.PublicKey) (string, error) { } // jwsSign signs the digest using the given key. -// It returns ErrUnsupportedKey if the key type is unknown. -// The hash is used only for RSA keys. +// The hash is unused for ECDSA keys. +// +// Note: non-stdlib crypto.Signer implementations are expected to return +// the signature in the format as specified in RFC7518. +// See https://tools.ietf.org/html/rfc7518 for more details. func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) { - switch key := key.(type) { - case *rsa.PrivateKey: - return key.Sign(rand.Reader, digest, hash) - case *ecdsa.PrivateKey: + if key, ok := key.(*ecdsa.PrivateKey); ok { + // The key.Sign method of ecdsa returns ASN1-encoded signature. + // So, we use the package Sign function instead + // to get R and S values directly and format the result accordingly. r, s, err := ecdsa.Sign(rand.Reader, key, digest) if err != nil { return nil, err @@ -118,18 +121,18 @@ func jwsSign(key crypto.Signer, hash crypto.Hash, digest []byte) ([]byte, error) copy(sig[size*2-len(sb):], sb) return sig, nil } - return nil, ErrUnsupportedKey + return key.Sign(rand.Reader, digest, hash) } // jwsHasher indicates suitable JWS algorithm name and a hash function // to use for signing a digest with the provided key. // It returns ("", 0) if the key is not supported. -func jwsHasher(key crypto.Signer) (string, crypto.Hash) { - switch key := key.(type) { - case *rsa.PrivateKey: +func jwsHasher(pub crypto.PublicKey) (string, crypto.Hash) { + switch pub := pub.(type) { + case *rsa.PublicKey: return "RS256", crypto.SHA256 - case *ecdsa.PrivateKey: - switch key.Params().Name { + case *ecdsa.PublicKey: + switch pub.Params().Name { case "P-256": return "ES256", crypto.SHA256 case "P-384": diff --git a/vendor/golang.org/x/crypto/acme/jws_test.go b/vendor/golang.org/x/crypto/acme/jws_test.go index 0ff0fb5a..ee30b1e1 100644 --- a/vendor/golang.org/x/crypto/acme/jws_test.go +++ b/vendor/golang.org/x/crypto/acme/jws_test.go @@ -5,6 +5,7 @@ package acme import ( + "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" @@ -13,6 +14,7 @@ import ( "encoding/json" "encoding/pem" "fmt" + "io" "math/big" "testing" ) @@ -241,6 +243,79 @@ func TestJWSEncodeJSONEC(t *testing.T) { } } +type customTestSigner struct { + sig []byte + pub crypto.PublicKey +} + +func (s *customTestSigner) Public() crypto.PublicKey { return s.pub } +func (s *customTestSigner) Sign(io.Reader, []byte, crypto.SignerOpts) ([]byte, error) { + return s.sig, nil +} + +func TestJWSEncodeJSONCustom(t *testing.T) { + claims := struct{ Msg string }{"hello"} + const ( + // printf '{"Msg":"hello"}' | base64 | tr -d '=' | tr '/+' '_-' + payload = "eyJNc2ciOiJoZWxsbyJ9" + // printf 'testsig' | base64 | tr -d '=' + testsig = "dGVzdHNpZw" + + // printf '{"alg":"ES256","jwk":{"crv":"P-256","kty":"EC","x":,"y":,"nonce":"nonce"}' | \ + // base64 | tr -d '=' | tr '/+' '_-' + es256phead = "eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjVsaEV1" + + "ZzV4SzR4QkRaMm5BYmF4THRhTGl2ODVieEo3ZVBkMWRrTzIzSFEiLCJ5IjoiNGFpSzcyc0JlVUFH" + + "a3YwVGFMc213b2tZVVl5TnhHc1M1RU1JS3dzTklLayJ9LCJub25jZSI6Im5vbmNlIn0" + + // {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"} + rs256phead = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" + + "IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" + + "SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" + + "QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" + + "VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" + + "NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" + + "QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" + + "bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" + + "ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" + + "b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" + + "UVEifSwibm9uY2UiOiJub25jZSJ9" + ) + + tt := []struct { + alg, phead string + pub crypto.PublicKey + }{ + {"RS256", rs256phead, testKey.Public()}, + {"ES256", es256phead, testKeyEC.Public()}, + } + for _, tc := range tt { + tc := tc + t.Run(tc.alg, func(t *testing.T) { + signer := &customTestSigner{ + sig: []byte("testsig"), + pub: tc.pub, + } + b, err := jwsEncodeJSON(claims, signer, "nonce") + if err != nil { + t.Fatal(err) + } + var j struct{ Protected, Payload, Signature string } + if err := json.Unmarshal(b, &j); err != nil { + t.Fatal(err) + } + if j.Protected != tc.phead { + t.Errorf("j.Protected = %q\nwant %q", j.Protected, tc.phead) + } + if j.Payload != payload { + t.Errorf("j.Payload = %q\nwant %q", j.Payload, payload) + } + if j.Signature != testsig { + t.Errorf("j.Signature = %q\nwant %q", j.Signature, testsig) + } + }) + } +} + func TestJWKThumbprintRSA(t *testing.T) { // Key example from RFC 7638 const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" + diff --git a/vendor/golang.org/x/crypto/acme/types.go b/vendor/golang.org/x/crypto/acme/types.go index 3e199749..54792c06 100644 --- a/vendor/golang.org/x/crypto/acme/types.go +++ b/vendor/golang.org/x/crypto/acme/types.go @@ -104,7 +104,7 @@ func RateLimit(err error) (time.Duration, bool) { if e.Header == nil { return 0, true } - return retryAfter(e.Header.Get("Retry-After"), 0), true + return retryAfter(e.Header.Get("Retry-After")), true } // Account is a user account. It is associated with a private key. @@ -296,8 +296,8 @@ func (e *wireError) error(h http.Header) *Error { } } -// CertOption is an optional argument type for the TLSSNIxChallengeCert methods for -// customizing a temporary certificate for TLS-SNI challenges. +// CertOption is an optional argument type for the TLS ChallengeCert methods for +// customizing a temporary certificate for TLS-based challenges. type CertOption interface { privateCertOpt() } @@ -317,7 +317,7 @@ func (*certOptKey) privateCertOpt() {} // WithTemplate creates an option for specifying a certificate template. // See x509.CreateCertificate for template usage details. // -// In TLSSNIxChallengeCert methods, the template is also used as parent, +// In TLS ChallengeCert methods, the template is also used as parent, // resulting in a self-signed certificate. // The DNSNames field of t is always overwritten for tls-sni challenge certs. func WithTemplate(t *x509.Certificate) CertOption { diff --git a/vendor/golang.org/x/crypto/argon2/argon2.go b/vendor/golang.org/x/crypto/argon2/argon2.go index 798f5cbd..b423feae 100644 --- a/vendor/golang.org/x/crypto/argon2/argon2.go +++ b/vendor/golang.org/x/crypto/argon2/argon2.go @@ -54,11 +54,12 @@ const ( // Key derives a key from the password, salt, and cost parameters using Argon2i // returning a byte slice of length keyLen that can be used as cryptographic -// key. The CPU cost and parallism degree must be greater than zero. +// key. The CPU cost and parallelism degree must be greater than zero. // // For example, you can get a derived key for e.g. AES-256 (which needs a -// 32-byte key) by doing: `key := argon2.Key([]byte("some password"), salt, 3, -// 32*1024, 4, 32)` +// 32-byte key) by doing: +// +// key := argon2.Key([]byte("some password"), salt, 3, 32*1024, 4, 32) // // The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number. // If using that amount of memory (32 MB) is not possible in some contexts then @@ -76,12 +77,13 @@ func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint3 // IDKey derives a key from the password, salt, and cost parameters using // Argon2id returning a byte slice of length keyLen that can be used as -// cryptographic key. The CPU cost and parallism degree must be greater than +// cryptographic key. The CPU cost and parallelism degree must be greater than // zero. // // For example, you can get a derived key for e.g. AES-256 (which needs a -// 32-byte key) by doing: `key := argon2.IDKey([]byte("some password"), salt, 1, -// 64*1024, 4, 32)` +// 32-byte key) by doing: +// +// key := argon2.IDKey([]byte("some password"), salt, 1, 64*1024, 4, 32) // // The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number. // If using that amount of memory (64 MB) is not possible in some contexts then diff --git a/vendor/golang.org/x/crypto/argon2/blamka_amd64.go b/vendor/golang.org/x/crypto/argon2/blamka_amd64.go index bb2b0d8b..2fc1ec03 100644 --- a/vendor/golang.org/x/crypto/argon2/blamka_amd64.go +++ b/vendor/golang.org/x/crypto/argon2/blamka_amd64.go @@ -6,12 +6,11 @@ package argon2 -func init() { - useSSE4 = supportsSSE4() -} +import "golang.org/x/sys/cpu" -//go:noescape -func supportsSSE4() bool +func init() { + useSSE4 = cpu.X86.HasSSE41 +} //go:noescape func mixBlocksSSE2(out, a, b, c *block) diff --git a/vendor/golang.org/x/crypto/argon2/blamka_amd64.s b/vendor/golang.org/x/crypto/argon2/blamka_amd64.s index 8a83f7c7..74a6e733 100644 --- a/vendor/golang.org/x/crypto/argon2/blamka_amd64.s +++ b/vendor/golang.org/x/crypto/argon2/blamka_amd64.s @@ -241,12 +241,3 @@ loop: SUBQ $2, BP JA loop RET - -// func supportsSSE4() bool -TEXT ·supportsSSE4(SB), 4, $0-1 - MOVL $1, AX - CPUID - SHRL $19, CX // Bit 19 indicates SSE4 support - ANDL $1, CX // CX != 0 if support SSE4 - MOVB CX, ret+0(FP) - RET diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go index aecf759e..b7162d82 100644 --- a/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go +++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go @@ -209,19 +209,19 @@ func TestMinorNotRequired(t *testing.T) { func BenchmarkEqual(b *testing.B) { b.StopTimer() passwd := []byte("somepasswordyoulike") - hash, _ := GenerateFromPassword(passwd, 10) + hash, _ := GenerateFromPassword(passwd, DefaultCost) b.StartTimer() for i := 0; i < b.N; i++ { CompareHashAndPassword(hash, passwd) } } -func BenchmarkGeneration(b *testing.B) { +func BenchmarkDefaultCost(b *testing.B) { b.StopTimer() passwd := []byte("mylongpassword1234") b.StartTimer() for i := 0; i < b.N; i++ { - GenerateFromPassword(passwd, 10) + GenerateFromPassword(passwd, DefaultCost) } } diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b.go b/vendor/golang.org/x/crypto/blake2b/blake2b.go index 6dedb894..58ea8753 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2b.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2b.go @@ -92,6 +92,8 @@ func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) } // values equal or greater than: // - 32 if BLAKE2b is used as a hash function (The key is zero bytes long). // - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long). +// When the key is nil, the returned hash.Hash implements BinaryMarshaler +// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash. func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) } func newDigest(hashSize int, key []byte) (*digest, error) { @@ -150,6 +152,50 @@ type digest struct { keyLen int } +const ( + magic = "b2b" + marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + if d.keyLen != 0 { + return nil, errors.New("crypto/blake2b: cannot marshal MACs") + } + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + for i := 0; i < 8; i++ { + b = appendUint64(b, d.h[i]) + } + b = appendUint64(b, d.c[0]) + b = appendUint64(b, d.c[1]) + // Maximum value for size is 64 + b = append(b, byte(d.size)) + b = append(b, d.block[:]...) + b = append(b, byte(d.offset)) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("crypto/blake2b: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("crypto/blake2b: invalid hash state size") + } + b = b[len(magic):] + for i := 0; i < 8; i++ { + b, d.h[i] = consumeUint64(b) + } + b, d.c[0] = consumeUint64(b) + b, d.c[1] = consumeUint64(b) + d.size = int(b[0]) + b = b[1:] + copy(d.block[:], b[:BlockSize]) + b = b[BlockSize:] + d.offset = int(b[0]) + return nil +} + func (d *digest) BlockSize() int { return BlockSize } func (d *digest) Size() int { return d.size } @@ -219,3 +265,25 @@ func (d *digest) finalize(hash *[Size]byte) { binary.LittleEndian.PutUint64(hash[8*i:], v) } } + +func appendUint64(b []byte, x uint64) []byte { + var a [8]byte + binary.BigEndian.PutUint64(a[:], x) + return append(b, a[:]...) +} + +func appendUint32(b []byte, x uint32) []byte { + var a [4]byte + binary.BigEndian.PutUint32(a[:], x) + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + x := binary.BigEndian.Uint64(b) + return b[8:], x +} + +func consumeUint32(b []byte) ([]byte, uint32) { + x := binary.BigEndian.Uint32(b) + return b[4:], x +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go index 8c41cf6c..4d31dd0f 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go @@ -6,21 +6,14 @@ package blake2b +import "golang.org/x/sys/cpu" + func init() { - useAVX2 = supportsAVX2() - useAVX = supportsAVX() - useSSE4 = supportsSSE4() + useAVX2 = cpu.X86.HasAVX2 + useAVX = cpu.X86.HasAVX + useSSE4 = cpu.X86.HasSSE41 } -//go:noescape -func supportsSSE4() bool - -//go:noescape -func supportsAVX() bool - -//go:noescape -func supportsAVX2() bool - //go:noescape func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) @@ -31,13 +24,14 @@ func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { - if useAVX2 { + switch { + case useAVX2: hashBlocksAVX2(h, c, flag, blocks) - } else if useAVX { + case useAVX: hashBlocksAVX(h, c, flag, blocks) - } else if useSSE4 { + case useSSE4: hashBlocksSSE4(h, c, flag, blocks) - } else { + default: hashBlocksGeneric(h, c, flag, blocks) } } diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s index 784bce6a..5593b1b3 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s @@ -748,15 +748,3 @@ noinc: MOVQ BP, SP RET - -// func supportsAVX2() bool -TEXT ·supportsAVX2(SB), 4, $0-1 - MOVQ runtime·support_avx2(SB), AX - MOVB AX, ret+0(FP) - RET - -// func supportsAVX() bool -TEXT ·supportsAVX(SB), 4, $0-1 - MOVQ runtime·support_avx(SB), AX - MOVB AX, ret+0(FP) - RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go index 2ab7c30f..30e2fcd5 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.go @@ -6,12 +6,11 @@ package blake2b -func init() { - useSSE4 = supportsSSE4() -} +import "golang.org/x/sys/cpu" -//go:noescape -func supportsSSE4() bool +func init() { + useSSE4 = cpu.X86.HasSSE41 +} //go:noescape func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s index 64530740..578e947b 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s @@ -279,12 +279,3 @@ noinc: MOVQ BP, SP RET - -// func supportsSSE4() bool -TEXT ·supportsSSE4(SB), 4, $0-1 - MOVL $1, AX - CPUID - SHRL $19, CX // Bit 19 indicates SSE4 support - ANDL $1, CX // CX != 0 if support SSE4 - MOVB CX, ret+0(FP) - RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_test.go b/vendor/golang.org/x/crypto/blake2b/blake2b_test.go index 5d68bbf6..723327ab 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2b_test.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_test.go @@ -6,6 +6,7 @@ package blake2b import ( "bytes" + "encoding" "encoding/hex" "fmt" "hash" @@ -69,6 +70,54 @@ func TestHashes2X(t *testing.T) { testHashes2X(t) } +func TestMarshal(t *testing.T) { + input := make([]byte, 255) + for i := range input { + input[i] = byte(i) + } + for _, size := range []int{Size, Size256, Size384, 12, 25, 63} { + for i := 0; i < 256; i++ { + h, err := New(size, nil) + if err != nil { + t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err) + } + h2, err := New(size, nil) + if err != nil { + t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err) + } + + h.Write(input[:i/2]) + halfstate, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Fatalf("size=%d, len(input)=%d: could not marshal: %v", size, i, err) + } + err = h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(halfstate) + if err != nil { + t.Fatalf("size=%d, len(input)=%d: could not unmarshal: %v", size, i, err) + } + + h.Write(input[i/2 : i]) + sum := h.Sum(nil) + h2.Write(input[i/2 : i]) + sum2 := h2.Sum(nil) + + if !bytes.Equal(sum, sum2) { + t.Fatalf("size=%d, len(input)=%d: results do not match; sum = %v, sum2 = %v", size, i, sum, sum2) + } + + h3, err := New(size, nil) + if err != nil { + t.Fatalf("size=%d, len(input)=%d: error from New(%v, nil): %v", size, i, size, err) + } + h3.Write(input[:i]) + sum3 := h3.Sum(nil) + if !bytes.Equal(sum, sum3) { + t.Fatalf("size=%d, len(input)=%d: sum = %v, want %v", size, i, sum, sum3) + } + } + } +} + func testHashes(t *testing.T) { key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f") diff --git a/vendor/golang.org/x/crypto/blake2b/blake2x.go b/vendor/golang.org/x/crypto/blake2b/blake2x.go index c814496a..52c414db 100644 --- a/vendor/golang.org/x/crypto/blake2b/blake2x.go +++ b/vendor/golang.org/x/crypto/blake2b/blake2x.go @@ -29,7 +29,7 @@ type XOF interface { } // OutputLengthUnknown can be used as the size argument to NewXOF to indicate -// the the length of the output is not known in advance. +// the length of the output is not known in advance. const OutputLengthUnknown = 0 // magicUnknownOutputLength is a magic value for the output size that indicates diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s.go b/vendor/golang.org/x/crypto/blake2s/blake2s.go index ae0dc922..5fb4a9ec 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2s.go +++ b/vendor/golang.org/x/crypto/blake2s/blake2s.go @@ -49,6 +49,8 @@ func Sum256(data []byte) [Size]byte { // New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil // key turns the hash into a MAC. The key must between zero and 32 bytes long. +// When the key is nil, the returned hash.Hash implements BinaryMarshaler +// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash. func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) } // New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a @@ -120,6 +122,50 @@ type digest struct { keyLen int } +const ( + magic = "b2s" + marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + if d.keyLen != 0 { + return nil, errors.New("crypto/blake2s: cannot marshal MACs") + } + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + for i := 0; i < 8; i++ { + b = appendUint32(b, d.h[i]) + } + b = appendUint32(b, d.c[0]) + b = appendUint32(b, d.c[1]) + // Maximum value for size is 32 + b = append(b, byte(d.size)) + b = append(b, d.block[:]...) + b = append(b, byte(d.offset)) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("crypto/blake2s: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("crypto/blake2s: invalid hash state size") + } + b = b[len(magic):] + for i := 0; i < 8; i++ { + b, d.h[i] = consumeUint32(b) + } + b, d.c[0] = consumeUint32(b) + b, d.c[1] = consumeUint32(b) + d.size = int(b[0]) + b = b[1:] + copy(d.block[:], b[:BlockSize]) + b = b[BlockSize:] + d.offset = int(b[0]) + return nil +} + func (d *digest) BlockSize() int { return BlockSize } func (d *digest) Size() int { return d.size } @@ -185,3 +231,14 @@ func (d *digest) finalize(hash *[Size]byte) { binary.LittleEndian.PutUint32(hash[4*i:], v) } } + +func appendUint32(b []byte, x uint32) []byte { + var a [4]byte + binary.BigEndian.PutUint32(a[:], x) + return append(b, a[:]...) +} + +func consumeUint32(b []byte) ([]byte, uint32) { + x := binary.BigEndian.Uint32(b) + return b[4:], x +} diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_386.go b/vendor/golang.org/x/crypto/blake2s/blake2s_386.go index 45ae5461..d8f9cea9 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2s_386.go +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_386.go @@ -6,18 +6,14 @@ package blake2s +import "golang.org/x/sys/cpu" + var ( useSSE4 = false - useSSSE3 = supportSSSE3() - useSSE2 = supportSSE2() + useSSSE3 = cpu.X86.HasSSSE3 + useSSE2 = cpu.X86.HasSSE2 ) -//go:noescape -func supportSSE2() bool - -//go:noescape -func supportSSSE3() bool - //go:noescape func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) @@ -25,11 +21,12 @@ func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) { - if useSSSE3 { + switch { + case useSSSE3: hashBlocksSSSE3(h, c, flag, blocks) - } else if useSSE2 { + case useSSE2: hashBlocksSSE2(h, c, flag, blocks) - } else { + default: hashBlocksGeneric(h, c, flag, blocks) } } diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_386.s b/vendor/golang.org/x/crypto/blake2s/blake2s_386.s index 0bb65c70..c123e5d6 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2s_386.s +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_386.s @@ -433,28 +433,3 @@ loop: MOVL BP, SP RET - -// func supportSSSE3() bool -TEXT ·supportSSSE3(SB), 4, $0-1 - MOVL $1, AX - CPUID - MOVL CX, BX - ANDL $0x1, BX // supports SSE3 - JZ FALSE - ANDL $0x200, CX // supports SSSE3 - JZ FALSE - MOVB $1, ret+0(FP) - RET - -FALSE: - MOVB $0, ret+0(FP) - RET - -// func supportSSE2() bool -TEXT ·supportSSE2(SB), 4, $0-1 - MOVL $1, AX - CPUID - SHRL $26, DX - ANDL $1, DX // DX != 0 if support SSE2 - MOVB DX, ret+0(FP) - RET diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go index a925e6b2..4e8d2d74 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.go @@ -6,18 +6,14 @@ package blake2s +import "golang.org/x/sys/cpu" + var ( - useSSE4 = supportSSE4() - useSSSE3 = supportSSSE3() - useSSE2 = true // Always available on amd64 + useSSE4 = cpu.X86.HasSSE41 + useSSSE3 = cpu.X86.HasSSSE3 + useSSE2 = cpu.X86.HasSSE2 ) -//go:noescape -func supportSSSE3() bool - -//go:noescape -func supportSSE4() bool - //go:noescape func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) @@ -28,13 +24,14 @@ func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) { - if useSSE4 { + switch { + case useSSE4: hashBlocksSSE4(h, c, flag, blocks) - } else if useSSSE3 { + case useSSSE3: hashBlocksSSSE3(h, c, flag, blocks) - } else if useSSE2 { + case useSSE2: hashBlocksSSE2(h, c, flag, blocks) - } else { + default: hashBlocksGeneric(h, c, flag, blocks) } } diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s index 6cdf5a94..8da28026 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_amd64.s @@ -436,28 +436,3 @@ TEXT ·hashBlocksSSSE3(SB), 0, $672-48 // frame = 656 + 16 byte alignment TEXT ·hashBlocksSSE4(SB), 0, $32-48 // frame = 16 + 16 byte alignment HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE4) RET - -// func supportSSE4() bool -TEXT ·supportSSE4(SB), 4, $0-1 - MOVL $1, AX - CPUID - SHRL $19, CX // Bit 19 indicates SSE4.1. - ANDL $1, CX - MOVB CX, ret+0(FP) - RET - -// func supportSSSE3() bool -TEXT ·supportSSSE3(SB), 4, $0-1 - MOVL $1, AX - CPUID - MOVL CX, BX - ANDL $0x1, BX // Bit zero indicates SSE3 support. - JZ FALSE - ANDL $0x200, CX // Bit nine indicates SSSE3 support. - JZ FALSE - MOVB $1, ret+0(FP) - RET - -FALSE: - MOVB $0, ret+0(FP) - RET diff --git a/vendor/golang.org/x/crypto/blake2s/blake2s_test.go b/vendor/golang.org/x/crypto/blake2s/blake2s_test.go index cfeb18bb..cde79fb1 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2s_test.go +++ b/vendor/golang.org/x/crypto/blake2s/blake2s_test.go @@ -5,6 +5,8 @@ package blake2s import ( + "bytes" + "encoding" "encoding/hex" "fmt" "testing" @@ -64,6 +66,52 @@ func TestHashes2X(t *testing.T) { testHashes2X(t) } +func TestMarshal(t *testing.T) { + input := make([]byte, 255) + for i := range input { + input[i] = byte(i) + } + for i := 0; i < 256; i++ { + h, err := New256(nil) + if err != nil { + t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err) + } + h2, err := New256(nil) + if err != nil { + t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err) + } + + h.Write(input[:i/2]) + halfstate, err := h.(encoding.BinaryMarshaler).MarshalBinary() + if err != nil { + t.Fatalf("len(input)=%d: could not marshal: %v", i, err) + } + err = h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(halfstate) + if err != nil { + t.Fatalf("len(input)=%d: could not unmarshal: %v", i, err) + } + + h.Write(input[i/2 : i]) + sum := h.Sum(nil) + h2.Write(input[i/2 : i]) + sum2 := h2.Sum(nil) + + if !bytes.Equal(sum, sum2) { + t.Fatalf("len(input)=%d: results do not match; sum = %v, sum2 = %v", i, sum, sum2) + } + + h3, err := New256(nil) + if err != nil { + t.Fatalf("len(input)=%d: error from New256(nil): %v", i, err) + } + h3.Write(input[:i]) + sum3 := h3.Sum(nil) + if !bytes.Equal(sum, sum3) { + t.Fatalf("len(input)=%d: sum = %v, want %v", i, sum, sum3) + } + } +} + func testHashes(t *testing.T) { key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f") diff --git a/vendor/golang.org/x/crypto/blake2s/blake2x.go b/vendor/golang.org/x/crypto/blake2s/blake2x.go index eaff2a7f..828749ff 100644 --- a/vendor/golang.org/x/crypto/blake2s/blake2x.go +++ b/vendor/golang.org/x/crypto/blake2s/blake2x.go @@ -29,7 +29,7 @@ type XOF interface { } // OutputLengthUnknown can be used as the size argument to NewXOF to indicate -// the the length of the output is not known in advance. +// the length of the output is not known in advance. const OutputLengthUnknown = 0 // magicUnknownOutputLength is a magic value for the output size that indicates diff --git a/vendor/golang.org/x/crypto/bn256/bn256.go b/vendor/golang.org/x/crypto/bn256/bn256.go index f88f3fc3..ff27febd 100644 --- a/vendor/golang.org/x/crypto/bn256/bn256.go +++ b/vendor/golang.org/x/crypto/bn256/bn256.go @@ -97,14 +97,18 @@ func (e *G1) Neg(a *G1) *G1 { // Marshal converts n to a byte slice. func (e *G1) Marshal() []byte { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if e.p.IsInfinity() { + return make([]byte, numBytes*2) + } + e.p.MakeAffine(nil) xBytes := new(big.Int).Mod(e.p.x, p).Bytes() yBytes := new(big.Int).Mod(e.p.y, p).Bytes() - // Each value is a 256-bit number. - const numBytes = 256 / 8 - ret := make([]byte, numBytes*2) copy(ret[1*numBytes-len(xBytes):], xBytes) copy(ret[2*numBytes-len(yBytes):], yBytes) @@ -205,6 +209,13 @@ func (e *G2) Add(a, b *G2) *G2 { // Marshal converts n into a byte slice. func (n *G2) Marshal() []byte { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if n.p.IsInfinity() { + return make([]byte, numBytes*4) + } + n.p.MakeAffine(nil) xxBytes := new(big.Int).Mod(n.p.x.x, p).Bytes() @@ -212,9 +223,6 @@ func (n *G2) Marshal() []byte { yxBytes := new(big.Int).Mod(n.p.y.x, p).Bytes() yyBytes := new(big.Int).Mod(n.p.y.y, p).Bytes() - // Each value is a 256-bit number. - const numBytes = 256 / 8 - ret := make([]byte, numBytes*4) copy(ret[1*numBytes-len(xxBytes):], xxBytes) copy(ret[2*numBytes-len(xyBytes):], xyBytes) diff --git a/vendor/golang.org/x/crypto/bn256/curve.go b/vendor/golang.org/x/crypto/bn256/curve.go index 55b7063f..63c052bc 100644 --- a/vendor/golang.org/x/crypto/bn256/curve.go +++ b/vendor/golang.org/x/crypto/bn256/curve.go @@ -245,10 +245,19 @@ func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoi return c } +// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets +// c to 0 : 1 : 0. func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint { if words := c.z.Bits(); len(words) == 1 && words[0] == 1 { return c } + if c.IsInfinity() { + c.x.SetInt64(0) + c.y.SetInt64(1) + c.z.SetInt64(0) + c.t.SetInt64(0) + return c + } zInv := pool.Get().ModInverse(c.z, p) t := pool.Get().Mul(c.y, zInv) diff --git a/vendor/golang.org/x/crypto/bn256/gfp12.go b/vendor/golang.org/x/crypto/bn256/gfp12.go index f084eddf..2b0151eb 100644 --- a/vendor/golang.org/x/crypto/bn256/gfp12.go +++ b/vendor/golang.org/x/crypto/bn256/gfp12.go @@ -125,8 +125,8 @@ func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 { } func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 { - e.x.Mul(e.x, b, pool) - e.y.Mul(e.y, b, pool) + e.x.Mul(a.x, b, pool) + e.y.Mul(a.y, b, pool) return e } diff --git a/vendor/golang.org/x/crypto/bn256/twist.go b/vendor/golang.org/x/crypto/bn256/twist.go index 4f8b3fed..056d80f1 100644 --- a/vendor/golang.org/x/crypto/bn256/twist.go +++ b/vendor/golang.org/x/crypto/bn256/twist.go @@ -219,10 +219,19 @@ func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoi return c } +// MakeAffine converts c to affine form and returns c. If c is ∞, then it sets +// c to 0 : 1 : 0. func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint { if c.z.IsOne() { return c } + if c.IsInfinity() { + c.x.SetZero() + c.y.SetOne() + c.z.SetZero() + c.t.SetZero() + return c + } zInv := newGFp2(pool).Invert(c.z, pool) t := newGFp2(pool).Mul(c.y, zInv, pool) diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go index 3f0dcb9d..bbb86efe 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go @@ -2,32 +2,50 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539. +// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539, +// and its extended nonce variant XChaCha20-Poly1305. package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305" import ( "crypto/cipher" + "encoding/binary" "errors" ) const ( // KeySize is the size of the key used by this AEAD, in bytes. KeySize = 32 - // NonceSize is the size of the nonce used with this AEAD, in bytes. + + // NonceSize is the size of the nonce used with the standard variant of this + // AEAD, in bytes. + // + // Note that this is too short to be safely generated at random if the same + // key is reused more than 2³² times. NonceSize = 12 + + // NonceSizeX is the size of the nonce used with the XChaCha20-Poly1305 + // variant of this AEAD, in bytes. + NonceSizeX = 24 ) type chacha20poly1305 struct { - key [32]byte + key [8]uint32 } -// New returns a ChaCha20-Poly1305 AEAD that uses the given, 256-bit key. +// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key. func New(key []byte) (cipher.AEAD, error) { if len(key) != KeySize { return nil, errors.New("chacha20poly1305: bad key length") } ret := new(chacha20poly1305) - copy(ret.key[:], key) + ret.key[0] = binary.LittleEndian.Uint32(key[0:4]) + ret.key[1] = binary.LittleEndian.Uint32(key[4:8]) + ret.key[2] = binary.LittleEndian.Uint32(key[8:12]) + ret.key[3] = binary.LittleEndian.Uint32(key[12:16]) + ret.key[4] = binary.LittleEndian.Uint32(key[16:20]) + ret.key[5] = binary.LittleEndian.Uint32(key[20:24]) + ret.key[6] = binary.LittleEndian.Uint32(key[24:28]) + ret.key[7] = binary.LittleEndian.Uint32(key[28:32]) return ret, nil } diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go index 7cd7ad83..2aa4fd89 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go @@ -6,7 +6,12 @@ package chacha20poly1305 -import "encoding/binary" +import ( + "encoding/binary" + + "golang.org/x/crypto/internal/subtle" + "golang.org/x/sys/cpu" +) //go:noescape func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool @@ -14,78 +19,26 @@ func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool //go:noescape func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte) -// cpuid is implemented in chacha20poly1305_amd64.s. -func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) - -// xgetbv with ecx = 0 is implemented in chacha20poly1305_amd64.s. -func xgetbv() (eax, edx uint32) - var ( - useASM bool - useAVX2 bool + useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2 ) -func init() { - detectCPUFeatures() -} - -// detectCPUFeatures is used to detect if cpu instructions -// used by the functions implemented in assembler in -// chacha20poly1305_amd64.s are supported. -func detectCPUFeatures() { - maxID, _, _, _ := cpuid(0, 0) - if maxID < 1 { - return - } - - _, _, ecx1, _ := cpuid(1, 0) - - haveSSSE3 := isSet(9, ecx1) - useASM = haveSSSE3 - - haveOSXSAVE := isSet(27, ecx1) - - osSupportsAVX := false - // For XGETBV, OSXSAVE bit is required and sufficient. - if haveOSXSAVE { - eax, _ := xgetbv() - // Check if XMM and YMM registers have OS support. - osSupportsAVX = isSet(1, eax) && isSet(2, eax) - } - haveAVX := isSet(28, ecx1) && osSupportsAVX - - if maxID < 7 { - return - } - - _, ebx7, _, _ := cpuid(7, 0) - haveAVX2 := isSet(5, ebx7) && haveAVX - haveBMI2 := isSet(8, ebx7) - - useAVX2 = haveAVX2 && haveBMI2 -} - -// isSet checks if bit at bitpos is set in value. -func isSet(bitpos uint, value uint32) bool { - return value&(1< 0 { - alterAdIdx := mr.Intn(len(ad)) + alterAdIdx := mathrand.Intn(len(ad)) ad[alterAdIdx] ^= 0x80 if _, err := aead.Open(nil, nonce, ct, ad); err == nil { t.Errorf("#%d: Open was successful after altering additional data", i) @@ -50,14 +65,14 @@ func TestVectors(t *testing.T) { ad[alterAdIdx] ^= 0x80 } - alterNonceIdx := mr.Intn(aead.NonceSize()) + alterNonceIdx := mathrand.Intn(aead.NonceSize()) nonce[alterNonceIdx] ^= 0x80 if _, err := aead.Open(nil, nonce, ct, ad); err == nil { t.Errorf("#%d: Open was successful after altering nonce", i) } nonce[alterNonceIdx] ^= 0x80 - alterCtIdx := mr.Intn(len(ct)) + alterCtIdx := mathrand.Intn(len(ct)) ct[alterCtIdx] ^= 0x80 if _, err := aead.Open(nil, nonce, ct, ad); err == nil { t.Errorf("#%d: Open was successful after altering ciphertext", i) @@ -68,87 +83,117 @@ func TestVectors(t *testing.T) { func TestRandom(t *testing.T) { // Some random tests to verify Open(Seal) == Plaintext - for i := 0; i < 256; i++ { - var nonce [12]byte - var key [32]byte + f := func(t *testing.T, nonceSize int) { + for i := 0; i < 256; i++ { + var nonce = make([]byte, nonceSize) + var key [32]byte - al := mr.Intn(128) - pl := mr.Intn(16384) - ad := make([]byte, al) - plaintext := make([]byte, pl) - cr.Read(key[:]) - cr.Read(nonce[:]) - cr.Read(ad) - cr.Read(plaintext) + al := mathrand.Intn(128) + pl := mathrand.Intn(16384) + ad := make([]byte, al) + plaintext := make([]byte, pl) + cryptorand.Read(key[:]) + cryptorand.Read(nonce[:]) + cryptorand.Read(ad) + cryptorand.Read(plaintext) - aead, err := New(key[:]) - if err != nil { - t.Fatal(err) - } - - ct := aead.Seal(nil, nonce[:], plaintext, ad) - - plaintext2, err := aead.Open(nil, nonce[:], ct, ad) - if err != nil { - t.Errorf("Random #%d: Open failed", i) - continue - } - - if !bytes.Equal(plaintext, plaintext2) { - t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext) - continue - } - - if len(ad) > 0 { - alterAdIdx := mr.Intn(len(ad)) - ad[alterAdIdx] ^= 0x80 - if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { - t.Errorf("Random #%d: Open was successful after altering additional data", i) + var ( + aead cipher.AEAD + err error + ) + switch len(nonce) { + case NonceSize: + aead, err = New(key[:]) + case NonceSizeX: + aead, err = NewX(key[:]) + default: + t.Fatalf("#%d: wrong nonce length: %d", i, len(nonce)) + } + if err != nil { + t.Fatal(err) } - ad[alterAdIdx] ^= 0x80 - } - alterNonceIdx := mr.Intn(aead.NonceSize()) - nonce[alterNonceIdx] ^= 0x80 - if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { - t.Errorf("Random #%d: Open was successful after altering nonce", i) - } - nonce[alterNonceIdx] ^= 0x80 + ct := aead.Seal(nil, nonce[:], plaintext, ad) - alterCtIdx := mr.Intn(len(ct)) - ct[alterCtIdx] ^= 0x80 - if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { - t.Errorf("Random #%d: Open was successful after altering ciphertext", i) + plaintext2, err := aead.Open(nil, nonce[:], ct, ad) + if err != nil { + t.Errorf("Random #%d: Open failed", i) + continue + } + + if !bytes.Equal(plaintext, plaintext2) { + t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext) + continue + } + + if len(ad) > 0 { + alterAdIdx := mathrand.Intn(len(ad)) + ad[alterAdIdx] ^= 0x80 + if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { + t.Errorf("Random #%d: Open was successful after altering additional data", i) + } + ad[alterAdIdx] ^= 0x80 + } + + alterNonceIdx := mathrand.Intn(aead.NonceSize()) + nonce[alterNonceIdx] ^= 0x80 + if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { + t.Errorf("Random #%d: Open was successful after altering nonce", i) + } + nonce[alterNonceIdx] ^= 0x80 + + alterCtIdx := mathrand.Intn(len(ct)) + ct[alterCtIdx] ^= 0x80 + if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil { + t.Errorf("Random #%d: Open was successful after altering ciphertext", i) + } + ct[alterCtIdx] ^= 0x80 } - ct[alterCtIdx] ^= 0x80 } + t.Run("Standard", func(t *testing.T) { f(t, NonceSize) }) + t.Run("X", func(t *testing.T) { f(t, NonceSizeX) }) } -func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte) { +func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte, nonceSize int) { + b.ReportAllocs() b.SetBytes(int64(len(buf))) var key [32]byte - var nonce [12]byte + var nonce = make([]byte, nonceSize) var ad [13]byte var out []byte - aead, _ := New(key[:]) + var aead cipher.AEAD + switch len(nonce) { + case NonceSize: + aead, _ = New(key[:]) + case NonceSizeX: + aead, _ = NewX(key[:]) + } + b.ResetTimer() for i := 0; i < b.N; i++ { out = aead.Seal(out[:0], nonce[:], buf[:], ad[:]) } } -func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) { +func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte, nonceSize int) { + b.ReportAllocs() b.SetBytes(int64(len(buf))) var key [32]byte - var nonce [12]byte + var nonce = make([]byte, nonceSize) var ad [13]byte var ct []byte var out []byte - aead, _ := New(key[:]) + var aead cipher.AEAD + switch len(nonce) { + case NonceSize: + aead, _ = New(key[:]) + case NonceSizeX: + aead, _ = NewX(key[:]) + } ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:]) b.ResetTimer() @@ -157,26 +202,54 @@ func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) { } } -func BenchmarkChacha20Poly1305Open_64(b *testing.B) { - benchamarkChaCha20Poly1305Open(b, make([]byte, 64)) +func BenchmarkChacha20Poly1305(b *testing.B) { + for _, length := range []int{64, 1350, 8 * 1024} { + b.Run("Open-"+strconv.Itoa(length), func(b *testing.B) { + benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSize) + }) + b.Run("Seal-"+strconv.Itoa(length), func(b *testing.B) { + benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSize) + }) + + b.Run("Open-"+strconv.Itoa(length)+"-X", func(b *testing.B) { + benchamarkChaCha20Poly1305Open(b, make([]byte, length), NonceSizeX) + }) + b.Run("Seal-"+strconv.Itoa(length)+"-X", func(b *testing.B) { + benchamarkChaCha20Poly1305Seal(b, make([]byte, length), NonceSizeX) + }) + } } -func BenchmarkChacha20Poly1305Seal_64(b *testing.B) { - benchamarkChaCha20Poly1305Seal(b, make([]byte, 64)) -} +var key = make([]byte, KeySize) -func BenchmarkChacha20Poly1305Open_1350(b *testing.B) { - benchamarkChaCha20Poly1305Open(b, make([]byte, 1350)) -} +func ExampleNewX() { + aead, err := NewX(key) + if err != nil { + log.Fatalln("Failed to instantiate XChaCha20-Poly1305:", err) + } -func BenchmarkChacha20Poly1305Seal_1350(b *testing.B) { - benchamarkChaCha20Poly1305Seal(b, make([]byte, 1350)) -} + for _, msg := range []string{ + "Attack at dawn.", + "The eagle has landed.", + "Gophers, gophers, gophers everywhere!", + } { + // Encryption. + nonce := make([]byte, NonceSizeX) + if _, err := cryptorand.Read(nonce); err != nil { + panic(err) + } + ciphertext := aead.Seal(nil, nonce, []byte(msg), nil) -func BenchmarkChacha20Poly1305Open_8K(b *testing.B) { - benchamarkChaCha20Poly1305Open(b, make([]byte, 8*1024)) -} + // Decryption. + plaintext, err := aead.Open(nil, nonce, ciphertext, nil) + if err != nil { + log.Fatalln("Failed to decrypt or authenticate message:", err) + } -func BenchmarkChacha20Poly1305Seal_8K(b *testing.B) { - benchamarkChaCha20Poly1305Seal(b, make([]byte, 8*1024)) + fmt.Printf("%s\n", plaintext) + } + + // Output: Attack at dawn. + // The eagle has landed. + // Gophers, gophers, gophers everywhere! } diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go index 49f0da6b..fa3607e8 100644 --- a/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go +++ b/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go @@ -7,6 +7,13 @@ package chacha20poly1305 var chacha20Poly1305Tests = []struct { plaintext, aad, key, nonce, out string }{ + { + "", + "", + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + "070000004041424344454647", + "a0784d7a4716f3feb4f64e7f4b39bf04", + }, { "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e", "50515253c0c1c2c3c4c5c6c7", @@ -329,4 +336,391 @@ var chacha20Poly1305Tests = []struct { "129039b5572e8a7a8131f76a", "2c125232a59879aee36cacc4aca5085a4688c4f776667a8fbd86862b5cfb1d57c976688fdd652eafa2b88b1b8e358aa2110ff6ef13cdc1ceca9c9f087c35c38d89d6fbd8de89538070f17916ecb19ca3ef4a1c834f0bdaa1df62aaabef2e117106787056c909e61ecd208357dd5c363f11c5d6cf24992cc873cf69f59360a820fcf290bd90b2cab24c47286acb4e1033962b6d41e562a206a94796a8ab1c6b8bade804ff9bdf5ba6062d2c1f8fe0f4dfc05720bd9a612b92c26789f9f6a7ce43f5e8e3aee99a9cd7d6c11eaa611983c36935b0dda57d898a60a0ab7c4b54", }, + + // XChaCha20-Poly1305 vectors + { + "000000000000000000000000000000", + "", + "0000000000000000000000000000000000000000000000000000000000000000", + "000000000000000000000000000000000000000000000000", + "789e9689e5208d7fd9e1f3c5b5341fb2f7033812ac9ebd3745e2c99c7bbfeb", + }, + { + "02dc819b71875e49f5e1e5a768141cfd3f14307ae61a34d81decd9a3367c00c7", + "", + "b7bbfe61b8041658ddc95d5cbdc01bbe7626d24f3a043b70ddee87541234cff7", + "e293239d4c0a07840c5f83cb515be7fd59c333933027e99c", + "7a51f271bd2e547943c7be3316c05519a5d16803712289aa2369950b1504dd8267222e47b13280077ecada7b8795d535", + }, + { + "7afc5f3f24155002e17dc176a8f1f3a097ff5a991b02ff4640f70b90db0c15c328b696d6998ea7988edfe3b960e47824e4ae002fbe589be57896a9b7bf5578599c6ba0153c7c", + "d499bb9758debe59a93783c61974b7", + "4ea8fab44a07f7ffc0329b2c2f8f994efdb6d505aec32113ae324def5d929ba1", + "404d5086271c58bf27b0352a205d21ce4367d7b6a7628961", + "26d2b46ad58b6988e2dcf1d09ba8ab6f532dc7e0847cdbc0ed00284225c02bbdb278ee8381ebd127a06926107d1b731cfb1521b267168926492e8f77219ad922257a5be2c5e52e6183ca4dfd0ad3912d7bd1ec968065", + }, + { + "", + "", + "48d8bd02c2e9947eae58327114d35e055407b5519c8019535efcb4fc875b5e2b", + "cc0a587a475caba06f8dbc09afec1462af081fe1908c2cba", + "fc3322d0a9d6fac3eb4a9e09b00b361e", + }, + { + "e0862731e5", + "", + "6579e7ee96151131a1fcd06fe0d52802c0021f214960ecceec14b2b8591f62cd", + "e2230748649bc22e2b71e46a7814ecabe3a7005e949bd491", + "e991efb85d8b1cfa3f92cb72b8d3c882e88f4529d9", + }, + { + "00c7dd8f440af1530b44", + "", + "ffb733657c849d50ab4ab40c4ae18f8ee2f0acf7c907afefdc04dff3537fdff3", + "02c6fd8032a8d89edbedcd1db024c09d29f08b1e74325085", + "13dbcdb8c60c3ed28449a57688edfaea89e309ab4faa6d51e532", + }, + { + "7422f311ea476cf819cb8b3c77369f", + "", + "ef0d05d028d6abdd5e99d1761d2028de75ee6eb376ff0dc8036e9a8e10743876", + "f772745200b0f92e38f1d8dae79bf8138e84b301f0be74df", + "d5f992f9834df1be86b580ac59c7eae063a68072829c51bc8a26970dd3d310", + }, + { + "ba09ca69450e6c7bece31a7a3f216e3b9ed0e536", + "", + "8d93e31abfe22a63faf45cbea91877050718f13fef6e2664a1892d7f23007ccf", + "260b7b3554a7e6ff8aae7dd6234077ca539689a20c1610a8", + "c99e9a768eb2ec8569bdff8a37295069552faebcafb1a76e98bc7c5b6b778b3d1b6291f0", + }, + { + "424ec5f98a0fdc5a7388532d11ab0edb26733505627b7f2d1f", + "", + "b68d5e6c46cdbb0060445522bdc5c562ae803b6aaaf1e103c146e93527a59299", + "80bb5dc1dd44a35ec4f91307f1a95b4ca31183a1a596fb7c", + "29d4eed0fff0050d4bb40de3b055d836206e7cbd62de1a63904f0cf731129ba3f9c2b9d46251a6de89", + }, + { + "e7e4515cc0a6ef0491af983eaac4f862d6e726758a3c657f4ec444841e42", + "", + "e31a1d3af650e8e2848bd78432d89ecd1fdece9842dc2792e7bda080f537b17b", + "f3f09905e9a871e757348834f483ed71be9c0f437c8d74b0", + "f5c69528963e17db725a28885d30a45194f12848b8b7644c7bded47a2ee83e6d4ef34006305cfdf82effdced461d", + }, + { + "0f5ca45a54875d1d19e952e53caeaa19389342f776dab11723535503338d6f77202a37", + "", + "1031bc920d4fcb4434553b1bf2d25ab375200643bf523ff037bf8914297e8dca", + "4cc77e2ef5445e07b5f44de2dc5bf62d35b8c6f69502d2bf", + "7aa8669e1bfe8b0688899cdddbb8cee31265928c66a69a5090478da7397573b1cc0f64121e7d8bff8db0ddd3c17460d7f29a12", + }, + { + "c45578c04c194994e89025c7ffb015e5f138be3cd1a93640af167706aee2ad25ad38696df41ad805", + "", + "ac8648b7c94328419c668ce1c57c71893adf73abbb98892a4fc8da17400e3a5e", + "4ad637facf97af5fc03207ae56219da9972858b7430b3611", + "49e093fcd074fb67a755669119b8bd430d98d9232ca988882deeb3508bde7c00160c35cea89092db864dcb6d440aefa5aacb8aa7b9c04cf0", + }, + { + "b877bfa192ea7e4c7569b9ee973f89924d45f9d8ed03c7098ad0cad6e7880906befedcaf6417bb43efabca7a2f", + "", + "125e331d5da423ecabc8adf693cdbc2fc3d3589740d40a3894f914db86c02492", + "913f8b2f08006e6260de41ec3ee01d938a3e68fb12dc44c4", + "1be334253423c90fc8ea885ee5cd3a54268c035ba8a2119e5bd4f7822cd7bf9cb4cec568d5b6d6292606d32979e044df3504e6eb8c0b2fc7e2a0e17d62", + }, + { + "d946484a1df5f85ff72c92ff9e192660cde5074bd0ddd5de900c35eb10ed991113b1b19884631bc8ceb386bcd83908061ce9", + "", + "b7e83276373dcf8929b6a6ea80314c9de871f5f241c9144189ee4caf62726332", + "f59f9d6e3e6c00720dc20dc21586e8330431ebf42cf9180e", + "a38a662b18c2d15e1b7b14443cc23267a10bee23556b084b6254226389c414069b694159a4d0b5abbe34de381a0e2c88b947b4cfaaebf50c7a1ad6c656e386280ad7", + }, + { + "d266927ca40b2261d5a4722f3b4da0dd5bec74e103fab431702309fd0d0f1a259c767b956aa7348ca923d64c04f0a2e898b0670988b15e", + "", + "a60e09cd0bea16f26e54b62b2908687aa89722c298e69a3a22cf6cf1c46b7f8a", + "92da9d67854c53597fc099b68d955be32df2f0d9efe93614", + "9dd6d05832f6b4d7f555a5a83930d6aed5423461d85f363efb6c474b6c4c8261b680dea393e24c2a3c8d1cc9db6df517423085833aa21f9ab5b42445b914f2313bcd205d179430", + }, + { + "f7e11b4d372ed7cb0c0e157f2f9488d8efea0f9bbe089a345f51bdc77e30d1392813c5d22ca7e2c7dfc2e2d0da67efb2a559058d4de7a11bd2a2915e", + "", + "194b1190fa31d483c222ec475d2d6117710dd1ac19a6f1a1e8e894885b7fa631", + "6b07ea26bb1f2d92e04207b447f2fd1dd2086b442a7b6852", + "25ae14585790d71d39a6e88632228a70b1f6a041839dc89a74701c06bfa7c4de3288b7772cb2919818d95777ab58fe5480d6e49958f5d2481431014a8f88dab8f7e08d2a9aebbe691430011d", + }, + { + "", + "1e2b11e3", + "70cd96817da85ede0efdf03a358103a84561b25453dee73735e5fb0161b0d493", + "5ddeba49f7266d11827a43931d1c300dd47a3c33f9f8bf9b", + "592fc4c19f3cddec517b2a00f9df9665", + }, + { + "81b3cb7eb3", + "efcfd0cf", + "a977412f889281a6d75c24186f1bfaa00dcc5132f0929f20ef15bbf9e63c4c91", + "3f26ca997fb9166d9c615babe3e543ca43ab7cab20634ac5", + "8e4ade3e254cf52e93eace5c46667f150832725594", + }, + { + "556f97f2ebdb4e949923", + "f7cee2e0", + "787b3e86546a51028501c801dadf8d5b996fd6f6f2363d5d0f900c44f6a2f4c2", + "7fa6af59a779657d1cada847439ea5b92a1337cfbebbc3b1", + "608ec22dae5f48b89d6f0d2a940d5a7661e0a8e68aaee4ad2d96", + }, + { + "c06847a36ad031595b60edd44dc245", + "d4175e1f", + "16de31e534dd5af32801b1acd0ec541d1f8d82bcbc3af25ec815f3575b7aca73", + "29f6656972838f56c1684f6a278f9e4e207b51d68706fc25", + "836082cc51303e500fceade0b1a18f1d97d64ff41cc81754c07d6231b9fd1b", + }, + { + "0d03c22ced7b29c6741e72166cd61792028dfc80", + "e505dad0", + "ac2b426e5c5c8e00666180a3410e8a2f6e52247a43aecea9622163e8433c93b2", + "c1123430468228625967bbc0fbd0f963e674372259ff2deb", + "bf09979bf4fed2eec6c97f6e1bcfac35eeffc6d54a55cc1d83d8767ae74db2d7cdfbc371", + }, + { + "05bf00e1707cffe7ccbd06a9f846d0fd471a700ed43b4facb8", + "d863bebe", + "66c121f0f84b95ba1e6d29e7d81900bc96a642421b9b6105ae5eb5f2e7b07577", + "8ed6ae211a661e967995b71f7316ba88f44322bb62b4187b", + "b2c5c85d087e0305e9058fba52b661fb3d7f21cb4d4915ae048bc9e5d66a2f921dd4a1c1b030f442c9", + }, + { + "5f2b91a9be8bfaa21451ddc6c5cf28d1cc00b046b76270b95cda3c280c83", + "a8750275", + "39592eb276877fca9dd11e2181c0b23127328407e3cc11e315e5d748f43529cc", + "1084bebd756f193d9eea608b3a0193a5028f8ced19684821", + "eaee1f49ac8468154c601a5dd8b84d597602e5a73534b5fad5664f97d0f017dd114752be969679cf610340c6a312", + }, + { + "01e8e269b5376943f3b2d245483a76461dc8b7634868b559165f5dbb20839029fae9bb", + "a1e96da0", + "b8386123b87e50d9d046242cf1bf141fce7f65aff0fba76861a2bc72582d6ff0", + "0fbe2a13a89bea031de96d78f9f11358ba7b6a5e724b4392", + "705ec3f910ec85c6005baa99641de6ca43332ff52b5466df6af4ffbe4ef2a376a8f871d1eae503b5896601fee005cdc1f4c1c6", + }, + { + "706daba66e2edb1f828f3c0051e3cc214b12210bde0587bba02580f741a4c83e84d4e9fe961120cd", + "87663c5a", + "d519d82ba8a3f0c3af9efe36682b62e285167be101a526c1d73000f169c2a486", + "ad651aac536978e2bc1a54816345ac5e9a9b43b3d9cc0bfc", + "07051b5e72da9c4811beb07ff9f95aece67eae18420eb3f0e8bb8a5e26d4b483fa40eb063a2354842d0c8a41d981cc2b77c530b496db01c8", + }, + { + "1f6b24f2f0d9eb460d726bed953d66fcc4ecc29da6ed2fd711358eac3b2609d74ba3e21885156cde3cbe6d9b6f", + "f5efbc4e", + "86068a00544f749ad4ad15bb8e427ae78577ae22f4ca9778efff828ba10f6b20", + "c8420412c9626dcd34ece14593730f6aa2d01ec51cacd59f", + "a99f6c88eac35bb34439e34b292fe9db8192446dcdc81e2192060ec36d98b47de2bee12bf0f67cb24fb0949c07733a6781cd9455cdc61123f506886b04", + }, + { + "d69389d83362be8c0ddb738659a6cc4bd65d88cb5b525232f4d59a7d4751a7203c254923ecb6873e803220aab19664789a63", + "bc35fb1c", + "835855b326a98682b3075b4d7f1b89059c3cdfc547d4296c80ce7a77ba6434e3", + "c27cb75fc319ba431cbaeb120341d0c4745d883eb47e92bc", + "db6dc3f9a0f4f1a6df2495a88910550c2c6205478bfc1e81282e34b5b36d984c72c0509c522c987c61d2e640ced69402a6d33aa10d3d0b81e680b3c19bc142e81923", + }, + { + "a66a7f089115ed9e2d5bb5d33d7282a7afe401269b00f2a233a59c04b794a42901d862140b61d18d7c7f0ad5da040613e557f8abc74219", + "2c060aaf", + "99758aa7714fd707931f71803eefe04a06955041308a0b2a1104313b270ccf34", + "63f690d8926408c7a34fe8ddd505a8dc58769dc74e8d5da6", + "92b21ee85afcd8996ac28f3aed1047ad814d6e4ffbca3159af16f26eded83e4abda9e4275eb3ff0ad90dffe09f2d443b628f824f680b46527ce0128e8de1920f7c44350ebe7913", + }, + { + "f955183b1f762d4536d3f6885ea7f5ac27414caf46c2e24a2fd3bd56b91c53d840fb657224565e0a6f686f8ba320e04a401057399d9a3d995ab17c13", + "c372ddc5", + "a188be3795b2ca2e69b6aa263244f0963c492d694cf6c9b705a1d7045f3f2a26", + "51bb484ea094ee140474681e1c838e4442fd148de2cc345a", + "48759a5ddfdd829d11de8e0c538ce4a9c475faab6912039b568ad92d737d172fc1eb0c00c3793de6dddbfacfdbbc7f44aeba33684e18005aa982b6fc6c556e63bb90ff7a1dde8153a63eabe0", + }, + { + "", + "e013cd0bfafd486d", + "af3d3ba094d38299ecb91c17bfe3d085da5bd42e11acf8acb5bc26a4be9a7583", + "7dd63c14173831f109761b1c1abe18f6ba937d825957011b", + "8bc685a7d9d501952295cd25d8c92517", + }, + { + "284b64597e", + "31d013e53aa3ea79", + "93c77409d7f805f97fe683b2dd6ee06152a5e918b3eed5b731acccffdcb2cc04", + "3d331e90c4597cf0c30d1b7cfbd07bcb6ab927eda056873c", + "3538a449d6c18d148a8c6cb76f1bc288657ac7036a", + }, + { + "9fe67f5c78180ede8274", + "188608d230d75860", + "b7cca89a82640aea6f80b458c9e633d88594fb498959d39787be87030892d48f", + "ef891d50e8c08958f814590fdb7a9f16c61cc2aae1682109", + "bbb40c30f3d1391a5b38df480cbbf964b71e763e8140751f4e28", + }, + { + "3a2826b6f7e3d542e4ded8f23c9aa4", + "260033e789c4676a", + "7fe2731214f2b4b42f93217d43f1776498413725e4f6cfe62b756e5a52df10ea", + "888728219ebf761547f5e2218532714403020e5a8b7a49d0", + "fe0328f883fcd88930ae017c0f54ed90f883041efc020e959125af370c1d47", + }, + { + "91858bf7b969005d7164acbd5678052b651c53e0", + "f3cc53ecafcbadb3", + "d69c04e9726b22d51f97bc9da0f0fda86736e6b78e8ef9f6f0000f79890d6d43", + "6de3c45161b434e05445cf6bf69eef7bddf595fc6d8836bd", + "a8869dd578c0835e120c843bb7dedc7a1e9eae24ffd742be6bf5b74088a8a2c550976fcb", + }, + { + "b3b1a4d6b2a2b9c5a1ca6c1efaec34dcfa1acbe7074d5e10cc", + "d0f72bd16cda3bae", + "2b317857b089c9305c49b83019f6e158bc4ecc3339b39ade02ee10c37c268da0", + "cb5fa6d1e14a0b4bdf350cd10c8a7bd638102911ec74be09", + "e6372f77c14343650074e07a2b7223c37b29242224b722b24d63b5956f27aa64ce7ce4e39cd14a2787", + }, + { + "057d3e9f865be7dff774938cab6d080e50cf9a1593f53c0063201e0bb7ae", + "fd3881e505c8b12d", + "36e42b1ef1ee8d068f09b5fad3ee43d98d34aa3e3f994f2055aee139da71de9d", + "24124da36473d01bdca30297c9eef4fe61955525a453da17", + "a8b28139524c98c1f8776f442eac4c22766fe6aac83224641c58bf021fc9cb709ec4706f49c2d0c1828acf2bfe8d", + }, + { + "bd8f13e928c34d67a6c70c3c7efdf2982ecc31d8cee68f9cbddc75912cd828ac93d28b", + "193206c8fcc5b19b", + "6e47c40c9d7b757c2efca4d73890e4c73f3c859aab4fdc64b564b8480dd84e72", + "ca31340ae20d30fe488be355cb36652c5db7c9d6265a3e95", + "a121efc5e1843deade4b8adbfef1808de4eda222f176630ad34fb476fca19e0299e4a13668e53cf13882035ba4f04f47c8b4e3", + }, + { + "23067a196e977d10039c14ff358061c918d2148d31961bb3e12c27c5122383cb25c4d1d79c775720", + "62338d02fff78a00", + "2c5c79c92d91fb40ef7d0a77e8033f7b265e3bab998b8116d17b2e62bb4f8a09", + "024736adb1d5c01006dffd8158b57936d158d5b42054336d", + "46d0905473a995d38c7cdbb8ef3da96ecc82a22c5b3c6c9d1c4a61ae7a17db53cb88c5f7eccf2da1d0c417c300f989b4273470e36f03542f", + }, + { + "252e966c680329eb687bff813b78fea3bfd3505333f106c6f9f45ba69896723c41bb763793d9b266e897d05557", + "1e93e0cfe6523380", + "9ec6fd1baa13ee16aec3fac16718a2baccf18a403cec467c25b7448e9b321110", + "e7120b1018ab363a36e61102eedbcbe9847a6cbacaa9c328", + "2934f034587d4144bb11182679cd2cd1c99c8088d18e233379e9bc9c41107a1f57a2723ecc7b9ba4e6ee198adf0fd766738e828827dc73136fc5b996e9", + }, + { + "6744aefcb318f12bc6eeb59d4d62f7eb95f347cea14bd5158415f07f84e4e3baa3de07512d9b76095ac1312cfcb1bb77f499", + "608d2a33ce5d0b04", + "0f665cbdaaa40f4f5a00c53d951b0a98aac2342be259a52670f650a783be7aab", + "378bdb57e957b8c2e1500c9513052a3b02ff5b7edbd4a3a7", + "341c60fcb374b394f1b01a4a80aedef49ab0b67ec963675e6eec43ef106f7003be87dbf4a8976709583dccc55abc7f979c4721837e8664a69804ea31736aa2af615a", + }, + { + "bcf1004f988220b7ce063ef2ec4e276ffd074f0a90aa807de1532679d2a1505568eaa4192d9a6ea52cc500322343ce9f8e68cc2c606d83", + "e64bd00126c8792c", + "58e65150d6a15dcefbc14a171998987ad0d709fb06a17d68d6a778759681c308", + "106d2bd120b06e4eb10bc674fe55c77a3742225268319303", + "a28052a6686a1e9435fee8702f7da563a7b3d7b5d3e9e27f11abf73db309cd1f39a34756258c1c5c7f2fb12cf15eb20175c2a08fc93dd19c5e482ef3fbef3d8404a3cfd54a7baf", + }, + { + "acd08d4938a224b4cb2d723bf75420f3ea27b698fadd815bb7db9548a05651398644354334e69f8e4e5503bf1a6f92b38e860044a7edca6874038ce1", + "28a137808d0225b8", + "a031203b963a395b08be55844d81af39d19b23b7cc24b21afa31edc1eea6edd6", + "e8b31c52b6690f10f4ae62ba9d50ba39fb5edcfb78400e35", + "35cf39ba31da95ac9b661cdbd5e9c9655d13b8ff065c4ec10c810833a47a87d8057dd1948a7801bfe6904b49fed0aabfb3cd755a1a262d372786908ddcf64cae9f71cb9ed199c3ddacc50116", + }, + { + "", + "cda7ee2857e09e9054ef6806", + "d91dffb18132d8dd3d144a2f10ba28bc5df36cb60369f3b19893ec91db3cf904", + "ee56f19c62b0438da6a0d9e01844313902be44f84a6a4ce7", + "ccd48b61a5683c195d4424009eb1d147", + }, + { + "350f4c7ac2", + "7c104b539c1d2ae022434cd6", + "cbb61e369117f9250f68fa707240c554359262a4d66c757f80e3aeb6920894fb", + "fbb14c9943444eac5413c6f5c8095451eddece02c9461043", + "b5c6a35865ed8e5216ff6c77339ee1ab570de50e51", + }, + { + "4f0d61d3ea03a44a8df0", + "51c20a8ae9e9794da931fe23", + "ba6ced943aa62f9261d7513b822e02054e099acafb5360f0d850064da48b5a4f", + "04c68cb50cdbb0ec03f8381cf59b886e64c40548bf8e3f82", + "ea45a73957e2a853655623f2a3bb58791f7ea36dd2957ed66ffa", + }, + { + "4fbdd4d4293a8f34fdbc8f3ad44cf6", + "8212f315e3759c3253c588bb", + "5354791bc2370415811818e913e310dd12e6a0cf5dcab2b6424816eecccf4b65", + "7ee6353c2fbc73c9ebc652270bc86e4008e09583e623e679", + "50a354811a918e1801fb567621a8924baf8dd79da6d36702855d3753f1319c", + }, + { + "5a6f68b5a9a9920ca9c6edf5be7c0af150a063c4", + "9a524aa62938fb7a1e50ed06", + "fd91605a6ad85d8ba7a71b08dce1032aa9992bf4f28d407a53ddda04c043cada", + "46791d99d6de33e79025bf9e97c198e7cf409614c6284b4d", + "648033c1eb615467e90b7d3ac24202d8b849549141f9bab03e9e910c29b8eab3d4fb3f2c", + }, + { + "d9318c2c0d9ed89e35d242a6b1d496e7e0c5bbdf77eba14c56", + "a16053c35fbe8dc93c14a81f", + "f21406aec83134ebf7bc48c6d0f45acb5f341fbc7d3b5a9bff3ea1333c916af7", + "de6b977be450d5efa7777e006802ddbb10814a22da1c3cd9", + "8d3dad487d5161663da830b71c3e24ec5cdb74d858cbb73b084ed0902198532aad3a18416966bff223", + }, + { + "68d0ee08d38cb4bcc9268fee3030666e70e41fcabf6fe06536eeec43eec5", + "11e09447d40b22dc98070eec", + "da5ee1ec02eab13220fcb94f16efec848a8dd57c0f4d67955423f5d17fde5aa3", + "8f13e61d773a250810f75d46bf163a3f9205be5751f6049a", + "92a103b03764c1ad1f88500d22eeae5c0fe1044c872987c0b97affc5e8c3d783f8cc28a11dc91990ea22dd1bad74", + }, + { + "a1d960bda08efcf19e136dc1e8b05b6b381c820eda5f9a8047e1a2dd1803a1e4d11a7f", + "aa73d8d4aaa0cfd9d80a9ae8", + "08028833d617c28ba75b48f177cb5da87189189abb68dcb8974eca9230c25945", + "f7b6f34a910fd11588f567de8555932291f7df05f6e2b193", + "99cfc4cca193998bae153b744e6c94a82a2867780aa0f43acddb7c433fcb297311313ec2199f00d7ca7da0646b40113c60e935", + }, + { + "3b4ae39a745b6247ce5baf675ec36c5065b1bf76c8379eab4b769961d43a753896d068938017777e", + "128c017a985052f8cdbc6b28", + "4683d5caff613187a9b16af897253848e9c54fc0ec319de62452a86961d3cbb2", + "5612a13c2da003b91188921cbac3fa093eba99d8cbbb51ff", + "91a98b93b2174257175f7c882b45cc252e0db8667612bd270c1c12fe28b6bf209760bf8f370318f92ae3f88a5d4773b05714132cc28dddb8", + }, + { + "22ccf680d2995ef6563de281cff76882a036a59ad73f250e710b3040590d69bccde8a8411abe8b0d3cb728ca82", + "13a97d0a167a61aa21e531ec", + "9e140762eed274948b66de25e6e8f36ab65dc730b0cb096ef15aaba900a5588c", + "d0e9594cfd42ab72553bf34062a263f588bb8f1fc86a19f5", + "f194fc866dfba30e42c4508b7d90b3fa3f8983831ede713334563e36aa861f2f885b40be1dbe20ba2d10958a12823588d4bbbefb81a87d87315204f5e3", + }, + { + "a65f5d10c482b3381af296e631eb605eba6a11ccec6ceab021460d0bd35feb676ec6dbba5d4ad6c9f4d683ea541035bc80fa", + "f15ae71ffed50a8fcc4996b0", + "f535d60e8b75ac7e526041eed86eb4d65ae7e315eff15dba6c0133acc2a6a4bf", + "01ba61691ebb3c66d2f94c1b1c597ecd7b5ff7d2a30be405", + "d79e7c3893df5a5879c2f0a3f7ca619f08e4540f3ac7db35790b4211b9d47ae735adadf35fd47252a4763e3fd2b2cd8157f6ea7986108a53437962670a97d68ee281", + }, + { + "8c014655b97f6da76b0b168b565fd62de874c164fd7e227346a0ec22c908bed1e2a0b429620e6f3a68dd518f13a2c0250608a1cb08a7c3", + "10a7eff999029c5040c1b3bd", + "bf11af23e88c350a443493f6fa0eb34f234f4daa2676e26f0701bce5642d13f4", + "f14c97392afd2e32e2c625910ca029f9b6e81676c79cc42f", + "78d5226f372d5d60681dbfc749d12df74249f196b0cbf14fa65a3a59dc65ae458455ec39baa1df3397afe752bb06f6f13bf03c99abda7a95c1d0b73fd92d5f888a5f6f889a9aea", + }, + { + "66234d7a5b71eef134d60eccf7d5096ee879a33983d6f7a575e3a5e3a4022edccffe7865dde20b5b0a37252e31cb9a3650c63e35b057a1bc200a5b5b", + "ccc2406f997bcae737ddd0f5", + "d009eeb5b9b029577b14d200b7687b655eedb7d74add488f092681787999d66d", + "99319712626b400f9458dbb7a9abc9f5810f25b47fc90b39", + "543a2bbf52fd999027ae7c297353f3ce986f810bc2382583d0a81fda5939e4c87b6e8d262790cd614d6f753d8035b32adf43acc7f6d4c2c44289538928564b6587c2fcb99de1d8e34ffff323", + }, } diff --git a/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go b/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go new file mode 100644 index 00000000..a02fa571 --- /dev/null +++ b/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go @@ -0,0 +1,104 @@ +// 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 chacha20poly1305 + +import ( + "crypto/cipher" + "encoding/binary" + "errors" + + "golang.org/x/crypto/internal/chacha20" +) + +type xchacha20poly1305 struct { + key [8]uint32 +} + +// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key. +// +// XChaCha20-Poly1305 is a ChaCha20-Poly1305 variant that takes a longer nonce, +// suitable to be generated randomly without risk of collisions. It should be +// preferred when nonce uniqueness cannot be trivially ensured, or whenever +// nonces are randomly generated. +func NewX(key []byte) (cipher.AEAD, error) { + if len(key) != KeySize { + return nil, errors.New("chacha20poly1305: bad key length") + } + ret := new(xchacha20poly1305) + ret.key[0] = binary.LittleEndian.Uint32(key[0:4]) + ret.key[1] = binary.LittleEndian.Uint32(key[4:8]) + ret.key[2] = binary.LittleEndian.Uint32(key[8:12]) + ret.key[3] = binary.LittleEndian.Uint32(key[12:16]) + ret.key[4] = binary.LittleEndian.Uint32(key[16:20]) + ret.key[5] = binary.LittleEndian.Uint32(key[20:24]) + ret.key[6] = binary.LittleEndian.Uint32(key[24:28]) + ret.key[7] = binary.LittleEndian.Uint32(key[28:32]) + return ret, nil +} + +func (*xchacha20poly1305) NonceSize() int { + return NonceSizeX +} + +func (*xchacha20poly1305) Overhead() int { + return 16 +} + +func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { + if len(nonce) != NonceSizeX { + panic("chacha20poly1305: bad nonce length passed to Seal") + } + + // XChaCha20-Poly1305 technically supports a 64-bit counter, so there is no + // size limit. However, since we reuse the ChaCha20-Poly1305 implementation, + // the second half of the counter is not available. This is unlikely to be + // an issue because the cipher.AEAD API requires the entire message to be in + // memory, and the counter overflows at 256 GB. + if uint64(len(plaintext)) > (1<<38)-64 { + panic("chacha20poly1305: plaintext too large") + } + + hNonce := [4]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + binary.LittleEndian.Uint32(nonce[12:16]), + } + c := &chacha20poly1305{ + key: chacha20.HChaCha20(&x.key, &hNonce), + } + // The first 4 bytes of the final nonce are unused counter space. + cNonce := make([]byte, NonceSize) + copy(cNonce[4:12], nonce[16:24]) + + return c.seal(dst, cNonce[:], plaintext, additionalData) +} + +func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + if len(nonce) != NonceSizeX { + panic("chacha20poly1305: bad nonce length passed to Open") + } + if len(ciphertext) < 16 { + return nil, errOpen + } + if uint64(len(ciphertext)) > (1<<38)-48 { + panic("chacha20poly1305: ciphertext too large") + } + + hNonce := [4]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + binary.LittleEndian.Uint32(nonce[12:16]), + } + c := &chacha20poly1305{ + key: chacha20.HChaCha20(&x.key, &hNonce), + } + // The first 4 bytes of the final nonce are unused counter space. + cNonce := make([]byte, NonceSize) + copy(cNonce[4:12], nonce[16:24]) + + return c.open(dst, cNonce[:], ciphertext, additionalData) +} diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1.go index 88ec8b4f..528b9bff 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/asn1.go +++ b/vendor/golang.org/x/crypto/cryptobyte/asn1.go @@ -23,6 +23,12 @@ func (b *Builder) AddASN1Int64(v int64) { b.addASN1Signed(asn1.INTEGER, v) } +// AddASN1Int64WithTag appends a DER-encoded ASN.1 INTEGER with the +// given tag. +func (b *Builder) AddASN1Int64WithTag(v int64, tag asn1.Tag) { + b.addASN1Signed(tag, v) +} + // AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION. func (b *Builder) AddASN1Enum(v int64) { b.addASN1Signed(asn1.ENUM, v) @@ -224,6 +230,9 @@ func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) { // String +// ReadASN1Boolean decodes an ASN.1 INTEGER and converts it to a boolean +// representation into out and advances. It reports whether the read +// was successful. func (s *String) ReadASN1Boolean(out *bool) bool { var bytes String if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 { @@ -245,8 +254,8 @@ func (s *String) ReadASN1Boolean(out *bool) bool { var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem() // ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does -// not point to an integer or to a big.Int, it panics. It returns true on -// success and false on error. +// not point to an integer or to a big.Int, it panics. It reports whether the +// read was successful. func (s *String) ReadASN1Integer(out interface{}) bool { if reflect.TypeOf(out).Kind() != reflect.Ptr { panic("out is not a pointer") @@ -359,8 +368,16 @@ func asn1Unsigned(out *uint64, n []byte) bool { return true } -// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns -// true on success and false on error. +// ReadASN1Int64WithTag decodes an ASN.1 INTEGER with the given tag into out +// and advances. It reports whether the read was successful and resulted in a +// value that can be represented in an int64. +func (s *String) ReadASN1Int64WithTag(out *int64, tag asn1.Tag) bool { + var bytes String + return s.ReadASN1(&bytes, tag) && checkASN1Integer(bytes) && asn1Signed(out, bytes) +} + +// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It reports +// whether the read was successful. func (s *String) ReadASN1Enum(out *int) bool { var bytes String var i int64 @@ -392,7 +409,7 @@ func (s *String) readBase128Int(out *int) bool { } // ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and -// advances. It returns true on success and false on error. +// advances. It reports whether the read was successful. func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) bool { var bytes String if !s.ReadASN1(&bytes, asn1.OBJECT_IDENTIFIER) || len(bytes) == 0 { @@ -431,7 +448,7 @@ func (s *String) ReadASN1ObjectIdentifier(out *encoding_asn1.ObjectIdentifier) b } // ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and -// advances. It returns true on success and false on error. +// advances. It reports whether the read was successful. func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool { var bytes String if !s.ReadASN1(&bytes, asn1.GeneralizedTime) { @@ -449,8 +466,8 @@ func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool { return true } -// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It -// returns true on success and false on error. +// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. +// It reports whether the read was successful. func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { var bytes String if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 { @@ -471,8 +488,8 @@ func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { } // ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It is -// an error if the BIT STRING is not a whole number of bytes. This function -// returns true on success and false on error. +// an error if the BIT STRING is not a whole number of bytes. It reports +// whether the read was successful. func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool { var bytes String if !s.ReadASN1(&bytes, asn1.BIT_STRING) || len(bytes) == 0 { @@ -489,14 +506,14 @@ func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool { // ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including // tag and length bytes) into out, and advances. The element must match the -// given tag. It returns true on success and false on error. +// given tag. It reports whether the read was successful. func (s *String) ReadASN1Bytes(out *[]byte, tag asn1.Tag) bool { return s.ReadASN1((*String)(out), tag) } // ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including // tag and length bytes) into out, and advances. The element must match the -// given tag. It returns true on success and false on error. +// given tag. It reports whether the read was successful. // // Tags greater than 30 are not supported (i.e. low-tag-number format only). func (s *String) ReadASN1(out *String, tag asn1.Tag) bool { @@ -509,7 +526,7 @@ func (s *String) ReadASN1(out *String, tag asn1.Tag) bool { // ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including // tag and length bytes) into out, and advances. The element must match the -// given tag. It returns true on success and false on error. +// given tag. It reports whether the read was successful. // // Tags greater than 30 are not supported (i.e. low-tag-number format only). func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool { @@ -521,8 +538,8 @@ func (s *String) ReadASN1Element(out *String, tag asn1.Tag) bool { } // ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including -// tag and length bytes) into out, sets outTag to its tag, and advances. It -// returns true on success and false on error. +// tag and length bytes) into out, sets outTag to its tag, and advances. +// It reports whether the read was successful. // // Tags greater than 30 are not supported (i.e. low-tag-number format only). func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool { @@ -531,14 +548,14 @@ func (s *String) ReadAnyASN1(out *String, outTag *asn1.Tag) bool { // ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element // (including tag and length bytes) into out, sets outTag to is tag, and -// advances. It returns true on success and false on error. +// advances. It reports whether the read was successful. // // Tags greater than 30 are not supported (i.e. low-tag-number format only). func (s *String) ReadAnyASN1Element(out *String, outTag *asn1.Tag) bool { return s.readASN1(out, outTag, false /* include header */) } -// PeekASN1Tag returns true if the next ASN.1 value on the string starts with +// PeekASN1Tag reports whether the next ASN.1 value on the string starts with // the given tag. func (s String) PeekASN1Tag(tag asn1.Tag) bool { if len(s) == 0 { @@ -547,7 +564,8 @@ func (s String) PeekASN1Tag(tag asn1.Tag) bool { return asn1.Tag(s[0]) == tag } -// SkipASN1 reads and discards an ASN.1 element with the given tag. +// SkipASN1 reads and discards an ASN.1 element with the given tag. It +// reports whether the operation was successful. func (s *String) SkipASN1(tag asn1.Tag) bool { var unused String return s.ReadASN1(&unused, tag) @@ -556,7 +574,7 @@ func (s *String) SkipASN1(tag asn1.Tag) bool { // ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.1 // element (not including tag and length bytes) tagged with the given tag into // out. It stores whether an element with the tag was found in outPresent, -// unless outPresent is nil. It returns true on success and false on error. +// unless outPresent is nil. It reports whether the read was successful. func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) bool { present := s.PeekASN1Tag(tag) if outPresent != nil { @@ -569,7 +587,7 @@ func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag asn1.Tag) b } // SkipOptionalASN1 advances s over an ASN.1 element with the given tag, or -// else leaves s unchanged. +// else leaves s unchanged. It reports whether the operation was successful. func (s *String) SkipOptionalASN1(tag asn1.Tag) bool { if !s.PeekASN1Tag(tag) { return true @@ -581,8 +599,8 @@ func (s *String) SkipOptionalASN1(tag asn1.Tag) bool { // ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER // explicitly tagged with tag into out and advances. If no element with a // matching tag is present, it writes defaultValue into out instead. If out -// does not point to an integer or to a big.Int, it panics. It returns true on -// success and false on error. +// does not point to an integer or to a big.Int, it panics. It reports +// whether the read was successful. func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool { if reflect.TypeOf(out).Kind() != reflect.Ptr { panic("out is not a pointer") @@ -619,8 +637,8 @@ func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultV // ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING // explicitly tagged with tag into out and advances. If no element with a -// matching tag is present, it writes defaultValue into out instead. It returns -// true on success and false on error. +// matching tag is present, it sets "out" to nil instead. It reports +// whether the read was successful. func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag asn1.Tag) bool { var present bool var child String @@ -644,6 +662,7 @@ func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag // ReadOptionalASN1Boolean sets *out to the value of the next ASN.1 BOOLEAN or, // if the next bytes are not an ASN.1 BOOLEAN, to the value of defaultValue. +// It reports whether the operation was successful. func (s *String) ReadOptionalASN1Boolean(out *bool, defaultValue bool) bool { var present bool var child String diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1_test.go b/vendor/golang.org/x/crypto/cryptobyte/asn1_test.go index ee6674a2..9f6c952a 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/asn1_test.go +++ b/vendor/golang.org/x/crypto/cryptobyte/asn1_test.go @@ -149,6 +149,39 @@ func TestReadASN1IntegerSigned(t *testing.T) { } } }) + + // Repeat with the implicit-tagging functions + t.Run("WithTag", func(t *testing.T) { + for i, test := range testData64 { + tag := asn1.Tag((i * 3) % 32).ContextSpecific() + + testData := make([]byte, len(test.in)) + copy(testData, test.in) + + // Alter the tag of the test case. + testData[0] = uint8(tag) + + in := String(testData) + var out int64 + ok := in.ReadASN1Int64WithTag(&out, tag) + if !ok || out != test.out { + t.Errorf("#%d: in.ReadASN1Int64WithTag() = %v, want true; out = %d, want %d", i, ok, out, test.out) + } + + var b Builder + b.AddASN1Int64WithTag(test.out, tag) + result, err := b.Bytes() + + if err != nil { + t.Errorf("#%d: AddASN1Int64WithTag failed: %s", i, err) + continue + } + + if !bytes.Equal(result, testData) { + t.Errorf("#%d: AddASN1Int64WithTag: got %x, want %x", i, result, testData) + } + } + }) } func TestReadASN1IntegerUnsigned(t *testing.T) { diff --git a/vendor/golang.org/x/crypto/cryptobyte/builder.go b/vendor/golang.org/x/crypto/cryptobyte/builder.go index 29b4c764..ca7b1db5 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/builder.go +++ b/vendor/golang.org/x/crypto/cryptobyte/builder.go @@ -50,8 +50,14 @@ func NewFixedBuilder(buffer []byte) *Builder { } } +// SetError sets the value to be returned as the error from Bytes. Writes +// performed after calling SetError are ignored. +func (b *Builder) SetError(err error) { + b.err = err +} + // Bytes returns the bytes written by the builder or an error if one has -// occurred during during building. +// occurred during building. func (b *Builder) Bytes() ([]byte, error) { if b.err != nil { return nil, b.err @@ -94,7 +100,7 @@ func (b *Builder) AddBytes(v []byte) { b.add(v...) } -// BuilderContinuation is continuation-passing interface for building +// BuilderContinuation is a continuation-passing interface for building // length-prefixed byte sequences. Builder methods for length-prefixed // sequences (AddUint8LengthPrefixed etc) will invoke the BuilderContinuation // supplied to them. The child builder passed to the continuation can be used @@ -268,9 +274,11 @@ func (b *Builder) flushChild() { return } - if !b.fixedSize { - b.result = child.result // In case child reallocated result. + if b.fixedSize && &b.result[0] != &child.result[0] { + panic("cryptobyte: BuilderContinuation reallocated a fixed-size buffer") } + + b.result = child.result } func (b *Builder) add(bytes ...byte) { @@ -278,7 +286,7 @@ func (b *Builder) add(bytes ...byte) { return } if b.child != nil { - panic("attempted write while child is pending") + panic("cryptobyte: attempted write while child is pending") } if len(b.result)+len(bytes) < len(bytes) { b.err = errors.New("cryptobyte: length overflow") @@ -290,6 +298,26 @@ func (b *Builder) add(bytes ...byte) { b.result = append(b.result, bytes...) } +// Unwrite rolls back n bytes written directly to the Builder. An attempt by a +// child builder passed to a continuation to unwrite bytes from its parent will +// panic. +func (b *Builder) Unwrite(n int) { + if b.err != nil { + return + } + if b.child != nil { + panic("cryptobyte: attempted unwrite while child is pending") + } + length := len(b.result) - b.pendingLenLen - b.offset + if length < 0 { + panic("cryptobyte: internal error") + } + if n > length { + panic("cryptobyte: attempted to unwrite more than was written") + } + b.result = b.result[:len(b.result)-n] +} + // A MarshalingValue marshals itself into a Builder. type MarshalingValue interface { // Marshal is called by Builder.AddValue. It receives a pointer to a builder diff --git a/vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go b/vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go index f294dd55..fb637091 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go +++ b/vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go @@ -327,12 +327,14 @@ func TestWriteWithPendingChild(t *testing.T) { var b Builder b.AddUint8LengthPrefixed(func(c *Builder) { c.AddUint8LengthPrefixed(func(d *Builder) { - defer func() { - if recover() == nil { - t.Errorf("recover() = nil, want error; c.AddUint8() did not panic") - } + func() { + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; c.AddUint8() did not panic") + } + }() + c.AddUint8(2) // panics }() - c.AddUint8(2) // panics defer func() { if recover() == nil { @@ -351,6 +353,92 @@ func TestWriteWithPendingChild(t *testing.T) { }) } +func TestSetError(t *testing.T) { + const errorStr = "TestSetError" + var b Builder + b.SetError(errors.New(errorStr)) + + ret, err := b.Bytes() + if ret != nil { + t.Error("expected nil result") + } + if err == nil { + t.Fatal("unexpected nil error") + } + if s := err.Error(); s != errorStr { + t.Errorf("expected error %q, got %v", errorStr, s) + } +} + +func TestUnwrite(t *testing.T) { + var b Builder + b.AddBytes([]byte{1, 2, 3, 4, 5}) + b.Unwrite(2) + if err := builderBytesEq(&b, 1, 2, 3); err != nil { + t.Error(err) + } + + func() { + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; b.Unwrite() did not panic") + } + }() + b.Unwrite(4) // panics + }() + + b = Builder{} + b.AddBytes([]byte{1, 2, 3, 4, 5}) + b.AddUint8LengthPrefixed(func(b *Builder) { + b.AddBytes([]byte{1, 2, 3, 4, 5}) + + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; b.Unwrite() did not panic") + } + }() + b.Unwrite(6) // panics + }) + + b = Builder{} + b.AddBytes([]byte{1, 2, 3, 4, 5}) + b.AddUint8LengthPrefixed(func(c *Builder) { + defer func() { + if recover() == nil { + t.Errorf("recover() = nil, want error; b.Unwrite() did not panic") + } + }() + b.Unwrite(2) // panics (attempted unwrite while child is pending) + }) +} + +func TestFixedBuilderLengthPrefixed(t *testing.T) { + bufCap := 10 + inner := bytes.Repeat([]byte{0xff}, bufCap-2) + buf := make([]byte, 0, bufCap) + b := NewFixedBuilder(buf) + b.AddUint16LengthPrefixed(func(b *Builder) { + b.AddBytes(inner) + }) + if got := b.BytesOrPanic(); len(got) != bufCap { + t.Errorf("Expected output length to be %d, got %d", bufCap, len(got)) + } +} + +func TestFixedBuilderPanicReallocate(t *testing.T) { + defer func() { + recover() + }() + + b := NewFixedBuilder(make([]byte, 0, 10)) + b1 := NewFixedBuilder(make([]byte, 0, 10)) + b.AddUint16LengthPrefixed(func(b *Builder) { + *b = *b1 + }) + + t.Error("Builder did not panic") +} + // ASN.1 func TestASN1Int64(t *testing.T) { diff --git a/vendor/golang.org/x/crypto/cryptobyte/string.go b/vendor/golang.org/x/crypto/cryptobyte/string.go index 7636fb9c..39bf98ae 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/string.go +++ b/vendor/golang.org/x/crypto/cryptobyte/string.go @@ -37,8 +37,8 @@ func (s *String) Skip(n int) bool { return s.read(n) != nil } -// ReadUint8 decodes an 8-bit value into out and advances over it. It -// returns true on success and false on error. +// ReadUint8 decodes an 8-bit value into out and advances over it. +// It reports whether the read was successful. func (s *String) ReadUint8(out *uint8) bool { v := s.read(1) if v == nil { @@ -49,7 +49,7 @@ func (s *String) ReadUint8(out *uint8) bool { } // ReadUint16 decodes a big-endian, 16-bit value into out and advances over it. -// It returns true on success and false on error. +// It reports whether the read was successful. func (s *String) ReadUint16(out *uint16) bool { v := s.read(2) if v == nil { @@ -60,7 +60,7 @@ func (s *String) ReadUint16(out *uint16) bool { } // ReadUint24 decodes a big-endian, 24-bit value into out and advances over it. -// It returns true on success and false on error. +// It reports whether the read was successful. func (s *String) ReadUint24(out *uint32) bool { v := s.read(3) if v == nil { @@ -71,7 +71,7 @@ func (s *String) ReadUint24(out *uint32) bool { } // ReadUint32 decodes a big-endian, 32-bit value into out and advances over it. -// It returns true on success and false on error. +// It reports whether the read was successful. func (s *String) ReadUint32(out *uint32) bool { v := s.read(4) if v == nil { @@ -119,28 +119,27 @@ func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool { } // ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value -// into out and advances over it. It returns true on success and false on -// error. +// into out and advances over it. It reports whether the read was successful. func (s *String) ReadUint8LengthPrefixed(out *String) bool { return s.readLengthPrefixed(1, out) } // ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit -// length-prefixed value into out and advances over it. It returns true on -// success and false on error. +// length-prefixed value into out and advances over it. It reports whether the +// read was successful. func (s *String) ReadUint16LengthPrefixed(out *String) bool { return s.readLengthPrefixed(2, out) } // ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit -// length-prefixed value into out and advances over it. It returns true on -// success and false on error. +// length-prefixed value into out and advances over it. It reports whether +// the read was successful. func (s *String) ReadUint24LengthPrefixed(out *String) bool { return s.readLengthPrefixed(3, out) } -// ReadBytes reads n bytes into out and advances over them. It returns true on -// success and false and error. +// ReadBytes reads n bytes into out and advances over them. It reports +// whether the read was successful. func (s *String) ReadBytes(out *[]byte, n int) bool { v := s.read(n) if v == nil { @@ -150,8 +149,8 @@ func (s *String) ReadBytes(out *[]byte, n int) bool { return true } -// CopyBytes copies len(out) bytes into out and advances over them. It returns -// true on success and false on error. +// CopyBytes copies len(out) bytes into out and advances over them. It reports +// whether the copy operation was successful func (s *String) CopyBytes(out []byte) bool { n := len(out) v := s.read(n) diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go index 4f26b49b..d6f683ba 100644 --- a/vendor/golang.org/x/crypto/ed25519/ed25519.go +++ b/vendor/golang.org/x/crypto/ed25519/ed25519.go @@ -6,7 +6,10 @@ // https://ed25519.cr.yp.to/. // // These functions are also compatible with the “Ed25519” function defined in -// RFC 8032. +// RFC 8032. However, unlike RFC 8032's formulation, this package's private key +// representation includes a public key suffix to make multiple signing +// operations with the same key more efficient. This package refers to the RFC +// 8032 private key as the “seed”. package ed25519 // This code is a port of the public domain, “ref10” implementation of ed25519 @@ -31,6 +34,8 @@ const ( PrivateKeySize = 64 // SignatureSize is the size, in bytes, of signatures generated and verified by this package. SignatureSize = 64 + // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032. + SeedSize = 32 ) // PublicKey is the type of Ed25519 public keys. @@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.PublicKey { return PublicKey(publicKey) } +// Seed returns the private key seed corresponding to priv. It is provided for +// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds +// in this package. +func (priv PrivateKey) Seed() []byte { + seed := make([]byte, SeedSize) + copy(seed, priv[:32]) + return seed +} + // Sign signs the given message with priv. // Ed25519 performs two passes over messages to be signed and therefore cannot // handle pre-hashed messages. Thus opts.HashFunc() must return zero to @@ -61,19 +75,33 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp // GenerateKey generates a public/private key pair using entropy from rand. // If rand is nil, crypto/rand.Reader will be used. -func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) { +func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) { if rand == nil { rand = cryptorand.Reader } - privateKey = make([]byte, PrivateKeySize) - publicKey = make([]byte, PublicKeySize) - _, err = io.ReadFull(rand, privateKey[:32]) - if err != nil { + seed := make([]byte, SeedSize) + if _, err := io.ReadFull(rand, seed); err != nil { return nil, nil, err } - digest := sha512.Sum512(privateKey[:32]) + privateKey := NewKeyFromSeed(seed) + publicKey := make([]byte, PublicKeySize) + copy(publicKey, privateKey[32:]) + + return publicKey, privateKey, nil +} + +// NewKeyFromSeed calculates a private key from a seed. It will panic if +// len(seed) is not SeedSize. This function is provided for interoperability +// with RFC 8032. RFC 8032's private keys correspond to seeds in this +// package. +func NewKeyFromSeed(seed []byte) PrivateKey { + if l := len(seed); l != SeedSize { + panic("ed25519: bad seed length: " + strconv.Itoa(l)) + } + + digest := sha512.Sum512(seed) digest[0] &= 248 digest[31] &= 127 digest[31] |= 64 @@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er var publicKeyBytes [32]byte A.ToBytes(&publicKeyBytes) + privateKey := make([]byte, PrivateKeySize) + copy(privateKey, seed) copy(privateKey[32:], publicKeyBytes[:]) - copy(publicKey, publicKeyBytes[:]) - return publicKey, privateKey, nil + return privateKey } // Sign signs the message with privateKey and returns a signature. It will @@ -171,9 +200,16 @@ func Verify(publicKey PublicKey, message, sig []byte) bool { edwards25519.ScReduce(&hReduced, &digest) var R edwards25519.ProjectiveGroupElement - var b [32]byte - copy(b[:], sig[32:]) - edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b) + var s [32]byte + copy(s[:], sig[32:]) + + // https://tools.ietf.org/html/rfc8032#section-5.1.7 requires that s be in + // the range [0, order) in order to prevent signature malleability. + if !edwards25519.ScMinimal(&s) { + return false + } + + edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &s) var checkR [32]byte R.ToBytes(&checkR) diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519_test.go b/vendor/golang.org/x/crypto/ed25519/ed25519_test.go index e272f8a5..80946036 100644 --- a/vendor/golang.org/x/crypto/ed25519/ed25519_test.go +++ b/vendor/golang.org/x/crypto/ed25519/ed25519_test.go @@ -139,6 +139,19 @@ func TestGolden(t *testing.T) { if !Verify(pubKey, msg, sig2) { t.Errorf("signature failed to verify on line %d", lineNo) } + + priv2 := NewKeyFromSeed(priv[:32]) + if !bytes.Equal(priv[:], priv2) { + t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2) + } + + if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) { + t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2) + } + + if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) { + t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed) + } } if err := scanner.Err(); err != nil { @@ -146,6 +159,30 @@ func TestGolden(t *testing.T) { } } +func TestMalleability(t *testing.T) { + // https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test + // that s be in [0, order). This prevents someone from adding a multiple of + // order to s and obtaining a second valid signature for the same message. + msg := []byte{0x54, 0x65, 0x73, 0x74} + sig := []byte{ + 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a, + 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b, + 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67, + 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d, + 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33, + 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d, + } + publicKey := []byte{ + 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5, + 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34, + 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa, + } + + if Verify(publicKey, msg, sig) { + t.Fatal("non-canonical signature accepted") + } +} + func BenchmarkKeyGeneration(b *testing.B) { var zero zeroReader for i := 0; i < b.N; i++ { diff --git a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go index 5f8b9947..fd03c252 100644 --- a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go +++ b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go @@ -4,6 +4,8 @@ package edwards25519 +import "encoding/binary" + // This code is a port of the public domain, “ref10” implementation of ed25519 // from SUPERCOP. @@ -1769,3 +1771,23 @@ func ScReduce(out *[32]byte, s *[64]byte) { out[30] = byte(s11 >> 9) out[31] = byte(s11 >> 17) } + +// order is the order of Curve25519 in little-endian form. +var order = [4]uint64{0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0, 0x1000000000000000} + +// ScMinimal returns true if the given scalar is less than the order of the +// curve. +func ScMinimal(scalar *[32]byte) bool { + for i := 3; ; i-- { + v := binary.LittleEndian.Uint64(scalar[i*8:]) + if v > order[i] { + return false + } else if v < order[i] { + break + } else if i == 0 { + return false + } + } + + return true +} diff --git a/vendor/golang.org/x/crypto/hkdf/example_test.go b/vendor/golang.org/x/crypto/hkdf/example_test.go index df843951..e89c260e 100644 --- a/vendor/golang.org/x/crypto/hkdf/example_test.go +++ b/vendor/golang.org/x/crypto/hkdf/example_test.go @@ -9,49 +9,44 @@ import ( "crypto/rand" "crypto/sha256" "fmt" - "golang.org/x/crypto/hkdf" "io" + + "golang.org/x/crypto/hkdf" ) -// Usage example that expands one master key into three other cryptographically -// secure keys. +// Usage example that expands one master secret into three other +// cryptographically secure keys. func Example_usage() { - // Underlying hash function to use + // Underlying hash function for HMAC. hash := sha256.New - // Cryptographically secure master key. - master := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this. + // Cryptographically secure master secret. + secret := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this. - // Non secret salt, optional (can be nil) - // Recommended: hash-length sized random + // Non-secret salt, optional (can be nil). + // Recommended: hash-length random value. salt := make([]byte, hash().Size()) - n, err := io.ReadFull(rand.Reader, salt) - if n != len(salt) || err != nil { - fmt.Println("error:", err) - return + if _, err := rand.Read(salt); err != nil { + panic(err) } - // Non secret context specific info, optional (can be nil). - // Note, independent from the master key. - info := []byte{0x03, 0x14, 0x15, 0x92, 0x65} + // Non-secret context info, optional (can be nil). + info := []byte("hkdf example") - // Create the key derivation function - hkdf := hkdf.New(hash, master, salt, info) + // Generate three 128-bit derived keys. + hkdf := hkdf.New(hash, secret, salt, info) - // Generate the required keys - keys := make([][]byte, 3) - for i := 0; i < len(keys); i++ { - keys[i] = make([]byte, 24) - n, err := io.ReadFull(hkdf, keys[i]) - if n != len(keys[i]) || err != nil { - fmt.Println("error:", err) - return + var keys [][]byte + for i := 0; i < 3; i++ { + key := make([]byte, 16) + if _, err := io.ReadFull(hkdf, key); err != nil { + panic(err) } + keys = append(keys, key) } - // Keys should contain 192 bit random keys - for i := 1; i <= len(keys); i++ { - fmt.Printf("Key #%d: %v\n", i, !bytes.Equal(keys[i-1], make([]byte, 24))) + for i := range keys { + fmt.Printf("Key #%d: %v\n", i+1, !bytes.Equal(keys[i], make([]byte, 16))) } // Output: diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf.go b/vendor/golang.org/x/crypto/hkdf/hkdf.go index 5bc24635..dda3f143 100644 --- a/vendor/golang.org/x/crypto/hkdf/hkdf.go +++ b/vendor/golang.org/x/crypto/hkdf/hkdf.go @@ -8,8 +8,6 @@ // HKDF is a cryptographic key derivation function (KDF) with the goal of // expanding limited input keying material into one or more cryptographically // strong secret keys. -// -// RFC 5869: https://tools.ietf.org/html/rfc5869 package hkdf // import "golang.org/x/crypto/hkdf" import ( @@ -19,6 +17,21 @@ import ( "io" ) +// Extract generates a pseudorandom key for use with Expand from an input secret +// and an optional independent salt. +// +// Only use this function if you need to reuse the extracted key with multiple +// Expand invocations and different context values. Most common scenarios, +// including the generation of multiple keys, should use New instead. +func Extract(hash func() hash.Hash, secret, salt []byte) []byte { + if salt == nil { + salt = make([]byte, hash().Size()) + } + extractor := hmac.New(hash, salt) + extractor.Write(secret) + return extractor.Sum(nil) +} + type hkdf struct { expander hash.Hash size int @@ -26,22 +39,22 @@ type hkdf struct { info []byte counter byte - prev []byte - cache []byte + prev []byte + buf []byte } func (f *hkdf) Read(p []byte) (int, error) { // Check whether enough data can be generated need := len(p) - remains := len(f.cache) + int(255-f.counter+1)*f.size + remains := len(f.buf) + int(255-f.counter+1)*f.size if remains < need { return 0, errors.New("hkdf: entropy limit reached") } - // Read from the cache, if enough data is present - n := copy(p, f.cache) + // Read any leftover from the buffer + n := copy(p, f.buf) p = p[n:] - // Fill the buffer + // Fill the rest of the buffer for len(p) > 0 { f.expander.Reset() f.expander.Write(f.prev) @@ -51,25 +64,30 @@ func (f *hkdf) Read(p []byte) (int, error) { f.counter++ // Copy the new batch into p - f.cache = f.prev - n = copy(p, f.cache) + f.buf = f.prev + n = copy(p, f.buf) p = p[n:] } // Save leftovers for next run - f.cache = f.cache[n:] + f.buf = f.buf[n:] return need, nil } -// New returns a new HKDF using the given hash, the secret keying material to expand -// and optional salt and info fields. -func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { - if salt == nil { - salt = make([]byte, hash().Size()) - } - extractor := hmac.New(hash, salt) - extractor.Write(secret) - prk := extractor.Sum(nil) - - return &hkdf{hmac.New(hash, prk), extractor.Size(), info, 1, nil, nil} +// Expand returns a Reader, from which keys can be read, using the given +// pseudorandom key and optional context info, skipping the extraction step. +// +// The pseudorandomKey should have been generated by Extract, or be a uniformly +// random or pseudorandom cryptographically strong key. See RFC 5869, Section +// 3.3. Most common scenarios will want to use New instead. +func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader { + expander := hmac.New(hash, pseudorandomKey) + return &hkdf{expander, expander.Size(), info, 1, nil, nil} +} + +// New returns a Reader, from which keys can be read, using the given hash, +// secret, salt and context info. Salt and info can be nil. +func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { + prk := Extract(hash, secret, salt) + return Expand(hash, prk, info) } diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf_test.go b/vendor/golang.org/x/crypto/hkdf/hkdf_test.go index cee659bc..ea575772 100644 --- a/vendor/golang.org/x/crypto/hkdf/hkdf_test.go +++ b/vendor/golang.org/x/crypto/hkdf/hkdf_test.go @@ -18,6 +18,7 @@ type hkdfTest struct { hash func() hash.Hash master []byte salt []byte + prk []byte info []byte out []byte } @@ -35,6 +36,12 @@ var hkdfTests = []hkdfTest{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, }, + []byte{ + 0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf, + 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63, + 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31, + 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5, + }, []byte{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, @@ -74,6 +81,12 @@ var hkdfTests = []hkdfTest{ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, }, + []byte{ + 0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a, + 0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c, + 0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01, + 0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44, + }, []byte{ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, @@ -108,6 +121,12 @@ var hkdfTests = []hkdfTest{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, }, []byte{}, + []byte{ + 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, + 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf, + 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, + 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04, + }, []byte{}, []byte{ 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, @@ -118,6 +137,30 @@ var hkdfTests = []hkdfTest{ 0x96, 0xc8, }, }, + { + sha256.New, + []byte{ + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + }, + nil, + []byte{ + 0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16, + 0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf, + 0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77, + 0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04, + }, + nil, + []byte{ + 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, + 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, + 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, + 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, + 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, + 0x96, 0xc8, + }, + }, { sha1.New, []byte{ @@ -128,6 +171,11 @@ var hkdfTests = []hkdfTest{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, }, + []byte{ + 0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f, + 0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4, 0xb3, 0x0b, + 0xaa, 0x2b, 0xa2, 0x43, + }, []byte{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, @@ -167,6 +215,11 @@ var hkdfTests = []hkdfTest{ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, }, + []byte{ + 0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59, + 0x47, 0x8d, 0x30, 0x9b, 0x26, 0xc4, 0x11, 0x5a, + 0x22, 0x4c, 0xfa, 0xf6, + }, []byte{ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, @@ -201,6 +254,11 @@ var hkdfTests = []hkdfTest{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, }, []byte{}, + []byte{ + 0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28, + 0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97, 0x78, 0x6a, + 0xa0, 0xd3, 0x2d, 0x01, + }, []byte{}, []byte{ 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, @@ -219,7 +277,12 @@ var hkdfTests = []hkdfTest{ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, }, nil, - []byte{}, + []byte{ + 0x2a, 0xdc, 0xca, 0xda, 0x18, 0x77, 0x9e, 0x7c, + 0x20, 0x77, 0xad, 0x2e, 0xb1, 0x9d, 0x3f, 0x3e, + 0x73, 0x13, 0x85, 0xdd, + }, + nil, []byte{ 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a, @@ -233,6 +296,11 @@ var hkdfTests = []hkdfTest{ func TestHKDF(t *testing.T) { for i, tt := range hkdfTests { + prk := Extract(tt.hash, tt.master, tt.salt) + if !bytes.Equal(prk, tt.prk) { + t.Errorf("test %d: incorrect PRK: have %v, need %v.", i, prk, tt.prk) + } + hkdf := New(tt.hash, tt.master, tt.salt, tt.info) out := make([]byte, len(tt.out)) @@ -244,6 +312,17 @@ func TestHKDF(t *testing.T) { if !bytes.Equal(out, tt.out) { t.Errorf("test %d: incorrect output: have %v, need %v.", i, out, tt.out) } + + hkdf = Expand(tt.hash, prk, tt.info) + + n, err = io.ReadFull(hkdf, out) + if n != len(tt.out) || err != nil { + t.Errorf("test %d: not enough output bytes from Expand: %d.", i, n) + } + + if !bytes.Equal(out, tt.out) { + t.Errorf("test %d: incorrect output from Expand: have %v, need %v.", i, out, tt.out) + } } } diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go index 0f8efdba..6570847f 100644 --- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_generic.go @@ -2,197 +2,263 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package ChaCha20 implements the core ChaCha20 function as specified in https://tools.ietf.org/html/rfc7539#section-2.3. +// Package ChaCha20 implements the core ChaCha20 function as specified +// in https://tools.ietf.org/html/rfc7539#section-2.3. package chacha20 -import "encoding/binary" +import ( + "crypto/cipher" + "encoding/binary" -const rounds = 20 + "golang.org/x/crypto/internal/subtle" +) -// core applies the ChaCha20 core function to 16-byte input in, 32-byte key k, -// and 16-byte constant c, and puts the result into 64-byte array out. -func core(out *[64]byte, in *[16]byte, k *[32]byte) { - j0 := uint32(0x61707865) - j1 := uint32(0x3320646e) - j2 := uint32(0x79622d32) - j3 := uint32(0x6b206574) - j4 := binary.LittleEndian.Uint32(k[0:4]) - j5 := binary.LittleEndian.Uint32(k[4:8]) - j6 := binary.LittleEndian.Uint32(k[8:12]) - j7 := binary.LittleEndian.Uint32(k[12:16]) - j8 := binary.LittleEndian.Uint32(k[16:20]) - j9 := binary.LittleEndian.Uint32(k[20:24]) - j10 := binary.LittleEndian.Uint32(k[24:28]) - j11 := binary.LittleEndian.Uint32(k[28:32]) - j12 := binary.LittleEndian.Uint32(in[0:4]) - j13 := binary.LittleEndian.Uint32(in[4:8]) - j14 := binary.LittleEndian.Uint32(in[8:12]) - j15 := binary.LittleEndian.Uint32(in[12:16]) +// assert that *Cipher implements cipher.Stream +var _ cipher.Stream = (*Cipher)(nil) - x0, x1, x2, x3, x4, x5, x6, x7 := j0, j1, j2, j3, j4, j5, j6, j7 - x8, x9, x10, x11, x12, x13, x14, x15 := j8, j9, j10, j11, j12, j13, j14, j15 +// Cipher is a stateful instance of ChaCha20 using a particular key +// and nonce. A *Cipher implements the cipher.Stream interface. +type Cipher struct { + key [8]uint32 + counter uint32 // incremented after each block + nonce [3]uint32 + buf [bufSize]byte // buffer for unused keystream bytes + len int // number of unused keystream bytes at end of buf +} - for i := 0; i < rounds; i += 2 { - x0 += x4 - x12 ^= x0 - x12 = (x12 << 16) | (x12 >> (16)) - x8 += x12 - x4 ^= x8 - x4 = (x4 << 12) | (x4 >> (20)) - x0 += x4 - x12 ^= x0 - x12 = (x12 << 8) | (x12 >> (24)) - x8 += x12 - x4 ^= x8 - x4 = (x4 << 7) | (x4 >> (25)) - x1 += x5 - x13 ^= x1 - x13 = (x13 << 16) | (x13 >> 16) - x9 += x13 - x5 ^= x9 - x5 = (x5 << 12) | (x5 >> 20) - x1 += x5 - x13 ^= x1 - x13 = (x13 << 8) | (x13 >> 24) - x9 += x13 - x5 ^= x9 - x5 = (x5 << 7) | (x5 >> 25) - x2 += x6 - x14 ^= x2 - x14 = (x14 << 16) | (x14 >> 16) - x10 += x14 - x6 ^= x10 - x6 = (x6 << 12) | (x6 >> 20) - x2 += x6 - x14 ^= x2 - x14 = (x14 << 8) | (x14 >> 24) - x10 += x14 - x6 ^= x10 - x6 = (x6 << 7) | (x6 >> 25) - x3 += x7 - x15 ^= x3 - x15 = (x15 << 16) | (x15 >> 16) - x11 += x15 - x7 ^= x11 - x7 = (x7 << 12) | (x7 >> 20) - x3 += x7 - x15 ^= x3 - x15 = (x15 << 8) | (x15 >> 24) - x11 += x15 - x7 ^= x11 - x7 = (x7 << 7) | (x7 >> 25) - x0 += x5 - x15 ^= x0 - x15 = (x15 << 16) | (x15 >> 16) - x10 += x15 - x5 ^= x10 - x5 = (x5 << 12) | (x5 >> 20) - x0 += x5 - x15 ^= x0 - x15 = (x15 << 8) | (x15 >> 24) - x10 += x15 - x5 ^= x10 - x5 = (x5 << 7) | (x5 >> 25) - x1 += x6 - x12 ^= x1 - x12 = (x12 << 16) | (x12 >> 16) - x11 += x12 - x6 ^= x11 - x6 = (x6 << 12) | (x6 >> 20) - x1 += x6 - x12 ^= x1 - x12 = (x12 << 8) | (x12 >> 24) - x11 += x12 - x6 ^= x11 - x6 = (x6 << 7) | (x6 >> 25) - x2 += x7 - x13 ^= x2 - x13 = (x13 << 16) | (x13 >> 16) - x8 += x13 - x7 ^= x8 - x7 = (x7 << 12) | (x7 >> 20) - x2 += x7 - x13 ^= x2 - x13 = (x13 << 8) | (x13 >> 24) - x8 += x13 - x7 ^= x8 - x7 = (x7 << 7) | (x7 >> 25) - x3 += x4 - x14 ^= x3 - x14 = (x14 << 16) | (x14 >> 16) - x9 += x14 - x4 ^= x9 - x4 = (x4 << 12) | (x4 >> 20) - x3 += x4 - x14 ^= x3 - x14 = (x14 << 8) | (x14 >> 24) - x9 += x14 - x4 ^= x9 - x4 = (x4 << 7) | (x4 >> 25) +// New creates a new ChaCha20 stream cipher with the given key and nonce. +// The initial counter value is set to 0. +func New(key [8]uint32, nonce [3]uint32) *Cipher { + return &Cipher{key: key, nonce: nonce} +} + +// ChaCha20 constants spelling "expand 32-byte k" +const ( + j0 uint32 = 0x61707865 + j1 uint32 = 0x3320646e + j2 uint32 = 0x79622d32 + j3 uint32 = 0x6b206574 +) + +func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) { + a += b + d ^= a + d = (d << 16) | (d >> 16) + c += d + b ^= c + b = (b << 12) | (b >> 20) + a += b + d ^= a + d = (d << 8) | (d >> 24) + c += d + b ^= c + b = (b << 7) | (b >> 25) + return a, b, c, d +} + +// XORKeyStream XORs each byte in the given slice with a byte from the +// cipher's key stream. Dst and src must overlap entirely or not at all. +// +// If len(dst) < len(src), XORKeyStream will panic. It is acceptable +// to pass a dst bigger than src, and in that case, XORKeyStream will +// only update dst[:len(src)] and will not touch the rest of dst. +// +// Multiple calls to XORKeyStream behave as if the concatenation of +// the src buffers was passed in a single run. That is, Cipher +// maintains state and does not reset at each XORKeyStream call. +func (s *Cipher) XORKeyStream(dst, src []byte) { + if len(dst) < len(src) { + panic("chacha20: output smaller than input") + } + if subtle.InexactOverlap(dst[:len(src)], src) { + panic("chacha20: invalid buffer overlap") } - x0 += j0 - x1 += j1 - x2 += j2 - x3 += j3 - x4 += j4 - x5 += j5 - x6 += j6 - x7 += j7 - x8 += j8 - x9 += j9 - x10 += j10 - x11 += j11 - x12 += j12 - x13 += j13 - x14 += j14 - x15 += j15 + // xor src with buffered keystream first + if s.len != 0 { + buf := s.buf[len(s.buf)-s.len:] + if len(src) < len(buf) { + buf = buf[:len(src)] + } + td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint + for i, b := range buf { + td[i] = ts[i] ^ b + } + s.len -= len(buf) + if s.len != 0 { + return + } + s.buf = [len(s.buf)]byte{} // zero the empty buffer + src = src[len(buf):] + dst = dst[len(buf):] + } - binary.LittleEndian.PutUint32(out[0:4], x0) - binary.LittleEndian.PutUint32(out[4:8], x1) - binary.LittleEndian.PutUint32(out[8:12], x2) - binary.LittleEndian.PutUint32(out[12:16], x3) - binary.LittleEndian.PutUint32(out[16:20], x4) - binary.LittleEndian.PutUint32(out[20:24], x5) - binary.LittleEndian.PutUint32(out[24:28], x6) - binary.LittleEndian.PutUint32(out[28:32], x7) - binary.LittleEndian.PutUint32(out[32:36], x8) - binary.LittleEndian.PutUint32(out[36:40], x9) - binary.LittleEndian.PutUint32(out[40:44], x10) - binary.LittleEndian.PutUint32(out[44:48], x11) - binary.LittleEndian.PutUint32(out[48:52], x12) - binary.LittleEndian.PutUint32(out[52:56], x13) - binary.LittleEndian.PutUint32(out[56:60], x14) - binary.LittleEndian.PutUint32(out[60:64], x15) + if len(src) == 0 { + return + } + if haveAsm { + if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 { + panic("chacha20: counter overflow") + } + s.xorKeyStreamAsm(dst, src) + return + } + + // set up a 64-byte buffer to pad out the final block if needed + // (hoisted out of the main loop to avoid spills) + rem := len(src) % 64 // length of final block + fin := len(src) - rem // index of final block + if rem > 0 { + copy(s.buf[len(s.buf)-64:], src[fin:]) + } + + // pre-calculate most of the first round + s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0]) + s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1]) + s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2]) + + n := len(src) + src, dst = src[:n:n], dst[:n:n] // BCE hint + for i := 0; i < n; i += 64 { + // calculate the remainder of the first round + s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter) + + // execute the second round + x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15) + x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12) + x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13) + x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14) + + // execute the remaining 18 rounds + for i := 0; i < 9; i++ { + x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) + x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) + x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) + x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) + + x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) + x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) + x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) + x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) + } + + x0 += j0 + x1 += j1 + x2 += j2 + x3 += j3 + + x4 += s.key[0] + x5 += s.key[1] + x6 += s.key[2] + x7 += s.key[3] + x8 += s.key[4] + x9 += s.key[5] + x10 += s.key[6] + x11 += s.key[7] + + x12 += s.counter + x13 += s.nonce[0] + x14 += s.nonce[1] + x15 += s.nonce[2] + + // increment the counter + s.counter += 1 + if s.counter == 0 { + panic("chacha20: counter overflow") + } + + // pad to 64 bytes if needed + in, out := src[i:], dst[i:] + if i == fin { + // src[fin:] has already been copied into s.buf before + // the main loop + in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:] + } + in, out = in[:64], out[:64] // BCE hint + + // XOR the key stream with the source and write out the result + xor(out[0:], in[0:], x0) + xor(out[4:], in[4:], x1) + xor(out[8:], in[8:], x2) + xor(out[12:], in[12:], x3) + xor(out[16:], in[16:], x4) + xor(out[20:], in[20:], x5) + xor(out[24:], in[24:], x6) + xor(out[28:], in[28:], x7) + xor(out[32:], in[32:], x8) + xor(out[36:], in[36:], x9) + xor(out[40:], in[40:], x10) + xor(out[44:], in[44:], x11) + xor(out[48:], in[48:], x12) + xor(out[52:], in[52:], x13) + xor(out[56:], in[56:], x14) + xor(out[60:], in[60:], x15) + } + // copy any trailing bytes out of the buffer and into dst + if rem != 0 { + s.len = 64 - rem + copy(dst[fin:], s.buf[len(s.buf)-64:]) + } +} + +// Advance discards bytes in the key stream until the next 64 byte block +// boundary is reached and updates the counter accordingly. If the key +// stream is already at a block boundary no bytes will be discarded and +// the counter will be unchanged. +func (s *Cipher) Advance() { + s.len -= s.len % 64 + if s.len == 0 { + s.buf = [len(s.buf)]byte{} + } } // XORKeyStream crypts bytes from in to out using the given key and counters. // In and out must overlap entirely or not at all. Counter contains the raw // ChaCha20 counter bytes (i.e. block counter followed by nonce). func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) { - var block [64]byte - var counterCopy [16]byte - copy(counterCopy[:], counter[:]) - - for len(in) >= 64 { - core(&block, &counterCopy, key) - for i, x := range block { - out[i] = in[i] ^ x - } - u := uint32(1) - for i := 0; i < 4; i++ { - u += uint32(counterCopy[i]) - counterCopy[i] = byte(u) - u >>= 8 - } - in = in[64:] - out = out[64:] - } - - if len(in) > 0 { - core(&block, &counterCopy, key) - for i, v := range in { - out[i] = v ^ block[i] - } + s := Cipher{ + key: [8]uint32{ + binary.LittleEndian.Uint32(key[0:4]), + binary.LittleEndian.Uint32(key[4:8]), + binary.LittleEndian.Uint32(key[8:12]), + binary.LittleEndian.Uint32(key[12:16]), + binary.LittleEndian.Uint32(key[16:20]), + binary.LittleEndian.Uint32(key[20:24]), + binary.LittleEndian.Uint32(key[24:28]), + binary.LittleEndian.Uint32(key[28:32]), + }, + nonce: [3]uint32{ + binary.LittleEndian.Uint32(counter[4:8]), + binary.LittleEndian.Uint32(counter[8:12]), + binary.LittleEndian.Uint32(counter[12:16]), + }, + counter: binary.LittleEndian.Uint32(counter[0:4]), } + s.XORKeyStream(out, in) +} + +// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a +// nonce. It should only be used as part of the XChaCha20 construction. +func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 { + x0, x1, x2, x3 := j0, j1, j2, j3 + x4, x5, x6, x7 := key[0], key[1], key[2], key[3] + x8, x9, x10, x11 := key[4], key[5], key[6], key[7] + x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3] + + for i := 0; i < 10; i++ { + x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12) + x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13) + x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14) + x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15) + + x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15) + x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12) + x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13) + x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14) + } + + var out [8]uint32 + out[0], out[1], out[2], out[3] = x0, x1, x2, x3 + out[4], out[5], out[6], out[7] = x12, x13, x14, x15 + return out } diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go new file mode 100644 index 00000000..91520d1d --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_noasm.go @@ -0,0 +1,16 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !s390x gccgo appengine + +package chacha20 + +const ( + bufSize = 64 + haveAsm = false +) + +func (*Cipher) xorKeyStreamAsm(dst, src []byte) { + panic("not implemented") +} diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go new file mode 100644 index 00000000..0c1c671c --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.go @@ -0,0 +1,30 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,!gccgo,!appengine + +package chacha20 + +var haveAsm = hasVectorFacility() + +const bufSize = 256 + +// hasVectorFacility reports whether the machine supports the vector +// facility (vx). +// Implementation in asm_s390x.s. +func hasVectorFacility() bool + +// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only +// be called when the vector facility is available. +// Implementation in asm_s390x.s. +//go:noescape +func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int) + +func (c *Cipher) xorKeyStreamAsm(dst, src []byte) { + xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len) +} + +// EXRL targets, DO NOT CALL! +func mvcSrcToBuf() +func mvcBufToDst() diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s new file mode 100644 index 00000000..98427c5e --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_s390x.s @@ -0,0 +1,283 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,!gccgo,!appengine + +#include "go_asm.h" +#include "textflag.h" + +// This is an implementation of the ChaCha20 encryption algorithm as +// specified in RFC 7539. It uses vector instructions to compute +// 4 keystream blocks in parallel (256 bytes) which are then XORed +// with the bytes in the input slice. + +GLOBL ·constants<>(SB), RODATA|NOPTR, $32 +// BSWAP: swap bytes in each 4-byte element +DATA ·constants<>+0x00(SB)/4, $0x03020100 +DATA ·constants<>+0x04(SB)/4, $0x07060504 +DATA ·constants<>+0x08(SB)/4, $0x0b0a0908 +DATA ·constants<>+0x0c(SB)/4, $0x0f0e0d0c +// J0: [j0, j1, j2, j3] +DATA ·constants<>+0x10(SB)/4, $0x61707865 +DATA ·constants<>+0x14(SB)/4, $0x3320646e +DATA ·constants<>+0x18(SB)/4, $0x79622d32 +DATA ·constants<>+0x1c(SB)/4, $0x6b206574 + +// EXRL targets: +TEXT ·mvcSrcToBuf(SB), NOFRAME|NOSPLIT, $0 + MVC $1, (R1), (R8) + RET + +TEXT ·mvcBufToDst(SB), NOFRAME|NOSPLIT, $0 + MVC $1, (R8), (R9) + RET + +#define BSWAP V5 +#define J0 V6 +#define KEY0 V7 +#define KEY1 V8 +#define NONCE V9 +#define CTR V10 +#define M0 V11 +#define M1 V12 +#define M2 V13 +#define M3 V14 +#define INC V15 +#define X0 V16 +#define X1 V17 +#define X2 V18 +#define X3 V19 +#define X4 V20 +#define X5 V21 +#define X6 V22 +#define X7 V23 +#define X8 V24 +#define X9 V25 +#define X10 V26 +#define X11 V27 +#define X12 V28 +#define X13 V29 +#define X14 V30 +#define X15 V31 + +#define NUM_ROUNDS 20 + +#define ROUND4(a0, a1, a2, a3, b0, b1, b2, b3, c0, c1, c2, c3, d0, d1, d2, d3) \ + VAF a1, a0, a0 \ + VAF b1, b0, b0 \ + VAF c1, c0, c0 \ + VAF d1, d0, d0 \ + VX a0, a2, a2 \ + VX b0, b2, b2 \ + VX c0, c2, c2 \ + VX d0, d2, d2 \ + VERLLF $16, a2, a2 \ + VERLLF $16, b2, b2 \ + VERLLF $16, c2, c2 \ + VERLLF $16, d2, d2 \ + VAF a2, a3, a3 \ + VAF b2, b3, b3 \ + VAF c2, c3, c3 \ + VAF d2, d3, d3 \ + VX a3, a1, a1 \ + VX b3, b1, b1 \ + VX c3, c1, c1 \ + VX d3, d1, d1 \ + VERLLF $12, a1, a1 \ + VERLLF $12, b1, b1 \ + VERLLF $12, c1, c1 \ + VERLLF $12, d1, d1 \ + VAF a1, a0, a0 \ + VAF b1, b0, b0 \ + VAF c1, c0, c0 \ + VAF d1, d0, d0 \ + VX a0, a2, a2 \ + VX b0, b2, b2 \ + VX c0, c2, c2 \ + VX d0, d2, d2 \ + VERLLF $8, a2, a2 \ + VERLLF $8, b2, b2 \ + VERLLF $8, c2, c2 \ + VERLLF $8, d2, d2 \ + VAF a2, a3, a3 \ + VAF b2, b3, b3 \ + VAF c2, c3, c3 \ + VAF d2, d3, d3 \ + VX a3, a1, a1 \ + VX b3, b1, b1 \ + VX c3, c1, c1 \ + VX d3, d1, d1 \ + VERLLF $7, a1, a1 \ + VERLLF $7, b1, b1 \ + VERLLF $7, c1, c1 \ + VERLLF $7, d1, d1 + +#define PERMUTE(mask, v0, v1, v2, v3) \ + VPERM v0, v0, mask, v0 \ + VPERM v1, v1, mask, v1 \ + VPERM v2, v2, mask, v2 \ + VPERM v3, v3, mask, v3 + +#define ADDV(x, v0, v1, v2, v3) \ + VAF x, v0, v0 \ + VAF x, v1, v1 \ + VAF x, v2, v2 \ + VAF x, v3, v3 + +#define XORV(off, dst, src, v0, v1, v2, v3) \ + VLM off(src), M0, M3 \ + PERMUTE(BSWAP, v0, v1, v2, v3) \ + VX v0, M0, M0 \ + VX v1, M1, M1 \ + VX v2, M2, M2 \ + VX v3, M3, M3 \ + VSTM M0, M3, off(dst) + +#define SHUFFLE(a, b, c, d, t, u, v, w) \ + VMRHF a, c, t \ // t = {a[0], c[0], a[1], c[1]} + VMRHF b, d, u \ // u = {b[0], d[0], b[1], d[1]} + VMRLF a, c, v \ // v = {a[2], c[2], a[3], c[3]} + VMRLF b, d, w \ // w = {b[2], d[2], b[3], d[3]} + VMRHF t, u, a \ // a = {a[0], b[0], c[0], d[0]} + VMRLF t, u, b \ // b = {a[1], b[1], c[1], d[1]} + VMRHF v, w, c \ // c = {a[2], b[2], c[2], d[2]} + VMRLF v, w, d // d = {a[3], b[3], c[3], d[3]} + +// func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int) +TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0 + MOVD $·constants<>(SB), R1 + MOVD dst+0(FP), R2 // R2=&dst[0] + LMG src+24(FP), R3, R4 // R3=&src[0] R4=len(src) + MOVD key+48(FP), R5 // R5=key + MOVD nonce+56(FP), R6 // R6=nonce + MOVD counter+64(FP), R7 // R7=counter + MOVD buf+72(FP), R8 // R8=buf + MOVD len+80(FP), R9 // R9=len + + // load BSWAP and J0 + VLM (R1), BSWAP, J0 + + // set up tail buffer + ADD $-1, R4, R12 + MOVBZ R12, R12 + CMPUBEQ R12, $255, aligned + MOVD R4, R1 + AND $~255, R1 + MOVD $(R3)(R1*1), R1 + EXRL $·mvcSrcToBuf(SB), R12 + MOVD $255, R0 + SUB R12, R0 + MOVD R0, (R9) // update len + +aligned: + // setup + MOVD $95, R0 + VLM (R5), KEY0, KEY1 + VLL R0, (R6), NONCE + VZERO M0 + VLEIB $7, $32, M0 + VSRLB M0, NONCE, NONCE + + // initialize counter values + VLREPF (R7), CTR + VZERO INC + VLEIF $1, $1, INC + VLEIF $2, $2, INC + VLEIF $3, $3, INC + VAF INC, CTR, CTR + VREPIF $4, INC + +chacha: + VREPF $0, J0, X0 + VREPF $1, J0, X1 + VREPF $2, J0, X2 + VREPF $3, J0, X3 + VREPF $0, KEY0, X4 + VREPF $1, KEY0, X5 + VREPF $2, KEY0, X6 + VREPF $3, KEY0, X7 + VREPF $0, KEY1, X8 + VREPF $1, KEY1, X9 + VREPF $2, KEY1, X10 + VREPF $3, KEY1, X11 + VLR CTR, X12 + VREPF $1, NONCE, X13 + VREPF $2, NONCE, X14 + VREPF $3, NONCE, X15 + + MOVD $(NUM_ROUNDS/2), R1 + +loop: + ROUND4(X0, X4, X12, X8, X1, X5, X13, X9, X2, X6, X14, X10, X3, X7, X15, X11) + ROUND4(X0, X5, X15, X10, X1, X6, X12, X11, X2, X7, X13, X8, X3, X4, X14, X9) + + ADD $-1, R1 + BNE loop + + // decrement length + ADD $-256, R4 + BLT tail + +continue: + // rearrange vectors + SHUFFLE(X0, X1, X2, X3, M0, M1, M2, M3) + ADDV(J0, X0, X1, X2, X3) + SHUFFLE(X4, X5, X6, X7, M0, M1, M2, M3) + ADDV(KEY0, X4, X5, X6, X7) + SHUFFLE(X8, X9, X10, X11, M0, M1, M2, M3) + ADDV(KEY1, X8, X9, X10, X11) + VAF CTR, X12, X12 + SHUFFLE(X12, X13, X14, X15, M0, M1, M2, M3) + ADDV(NONCE, X12, X13, X14, X15) + + // increment counters + VAF INC, CTR, CTR + + // xor keystream with plaintext + XORV(0*64, R2, R3, X0, X4, X8, X12) + XORV(1*64, R2, R3, X1, X5, X9, X13) + XORV(2*64, R2, R3, X2, X6, X10, X14) + XORV(3*64, R2, R3, X3, X7, X11, X15) + + // increment pointers + MOVD $256(R2), R2 + MOVD $256(R3), R3 + + CMPBNE R4, $0, chacha + CMPUBEQ R12, $255, return + EXRL $·mvcBufToDst(SB), R12 // len was updated during setup + +return: + VSTEF $0, CTR, (R7) + RET + +tail: + MOVD R2, R9 + MOVD R8, R2 + MOVD R8, R3 + MOVD $0, R4 + JMP continue + +// func hasVectorFacility() bool +TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 + MOVD $x-24(SP), R1 + XC $24, 0(R1), 0(R1) // clear the storage + MOVD $2, R0 // R0 is the number of double words stored -1 + WORD $0xB2B01000 // STFLE 0(R1) + XOR R0, R0 // reset the value of R0 + MOVBZ z-8(SP), R1 + AND $0x40, R1 + BEQ novector + +vectorinstalled: + // check if the vector instruction has been enabled + VLEIB $0, $0xF, V16 + VLGVB $0, V16, R1 + CMPBNE R1, $0xF, novector + MOVB $1, ret+0(FP) // have vx + RET + +novector: + MOVB $0, ret+0(FP) // no vx + RET diff --git a/vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go b/vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go index b80d34cd..9a7a0994 100644 --- a/vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go +++ b/vendor/golang.org/x/crypto/internal/chacha20/chacha_test.go @@ -5,7 +5,10 @@ package chacha20 import ( + "encoding/binary" "encoding/hex" + "fmt" + "math/rand" "testing" ) @@ -31,3 +34,192 @@ func TestCore(t *testing.T) { t.Errorf("wanted %x but got %x", expected, result) } } + +// Run the test cases with the input and output in different buffers. +func TestNoOverlap(t *testing.T) { + for _, c := range testVectors { + s := New(c.key, c.nonce) + input, err := hex.DecodeString(c.input) + if err != nil { + t.Fatalf("cannot decode input %#v: %v", c.input, err) + } + output := make([]byte, c.length) + s.XORKeyStream(output, input) + got := hex.EncodeToString(output) + if got != c.output { + t.Errorf("length=%v: got %#v, want %#v", c.length, got, c.output) + } + } +} + +// Run the test cases with the input and output overlapping entirely. +func TestOverlap(t *testing.T) { + for _, c := range testVectors { + s := New(c.key, c.nonce) + data, err := hex.DecodeString(c.input) + if err != nil { + t.Fatalf("cannot decode input %#v: %v", c.input, err) + } + s.XORKeyStream(data, data) + got := hex.EncodeToString(data) + if got != c.output { + t.Errorf("length=%v: got %#v, want %#v", c.length, got, c.output) + } + } +} + +// Run the test cases with various source and destination offsets. +func TestUnaligned(t *testing.T) { + const max = 8 // max offset (+1) to test + for _, c := range testVectors { + input := make([]byte, c.length+max) + output := make([]byte, c.length+max) + for i := 0; i < max; i++ { // input offsets + for j := 0; j < max; j++ { // output offsets + s := New(c.key, c.nonce) + + input := input[i : i+c.length] + output := output[j : j+c.length] + + data, err := hex.DecodeString(c.input) + if err != nil { + t.Fatalf("cannot decode input %#v: %v", c.input, err) + } + copy(input, data) + s.XORKeyStream(output, input) + got := hex.EncodeToString(output) + if got != c.output { + t.Errorf("length=%v: got %#v, want %#v", c.length, got, c.output) + } + } + } + } +} + +// Run the test cases by calling XORKeyStream multiple times. +func TestStep(t *testing.T) { + // wide range of step sizes to try and hit edge cases + steps := [...]int{1, 3, 4, 7, 8, 17, 24, 30, 64, 256} + rnd := rand.New(rand.NewSource(123)) + for _, c := range testVectors { + s := New(c.key, c.nonce) + input, err := hex.DecodeString(c.input) + if err != nil { + t.Fatalf("cannot decode input %#v: %v", c.input, err) + } + output := make([]byte, c.length) + + // step through the buffers + i, step := 0, steps[rnd.Intn(len(steps))] + for i+step < c.length { + s.XORKeyStream(output[i:i+step], input[i:i+step]) + if i+step < c.length && output[i+step] != 0 { + t.Errorf("length=%v, i=%v, step=%v: output overwritten", c.length, i, step) + } + i += step + step = steps[rnd.Intn(len(steps))] + } + // finish the encryption + s.XORKeyStream(output[i:], input[i:]) + + got := hex.EncodeToString(output) + if got != c.output { + t.Errorf("length=%v: got %#v, want %#v", c.length, got, c.output) + } + } +} + +// Test that Advance() discards bytes until a block boundary is hit. +func TestAdvance(t *testing.T) { + for _, c := range testVectors { + for i := 0; i < 63; i++ { + s := New(c.key, c.nonce) + z := New(c.key, c.nonce) + input, err := hex.DecodeString(c.input) + if err != nil { + t.Fatalf("cannot decode input %#v: %v", c.input, err) + } + zeros, discard := make([]byte, 64), make([]byte, 64) + so, zo := make([]byte, c.length), make([]byte, c.length) + for j := 0; j < c.length; j += 64 { + lim := j + i + if lim > c.length { + lim = c.length + } + s.XORKeyStream(so[j:lim], input[j:lim]) + // calling s.Advance() multiple times should have no effect + for k := 0; k < i%3+1; k++ { + s.Advance() + } + z.XORKeyStream(zo[j:lim], input[j:lim]) + if lim < c.length { + end := 64 - i + if c.length-lim < end { + end = c.length - lim + } + z.XORKeyStream(discard[:], zeros[:end]) + } + } + + got := hex.EncodeToString(so) + want := hex.EncodeToString(zo) + if got != want { + t.Errorf("length=%v: got %#v, want %#v", c.length, got, want) + } + } + } +} + +func BenchmarkChaCha20(b *testing.B) { + sizes := []int{32, 63, 64, 256, 1024, 1350, 65536} + for _, size := range sizes { + s := size + b.Run(fmt.Sprint(s), func(b *testing.B) { + k := [32]byte{} + c := [16]byte{} + src := make([]byte, s) + dst := make([]byte, s) + b.SetBytes(int64(s)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + XORKeyStream(dst, src, &c, &k) + } + }) + } +} + +func TestHChaCha20(t *testing.T) { + // See draft-paragon-paseto-rfc-00 §7.2.1. + key := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f} + nonce := []byte{0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x00, 0x31, 0x41, 0x59, 0x27} + expected := []byte{0x82, 0x41, 0x3b, 0x42, 0x27, 0xb2, 0x7b, 0xfe, + 0xd3, 0x0e, 0x42, 0x50, 0x8a, 0x87, 0x7d, 0x73, + 0xa0, 0xf9, 0xe4, 0xd5, 0x8a, 0x74, 0xa8, 0x53, + 0xc1, 0x2e, 0xc4, 0x13, 0x26, 0xd3, 0xec, 0xdc, + } + result := HChaCha20(&[8]uint32{ + binary.LittleEndian.Uint32(key[0:4]), + binary.LittleEndian.Uint32(key[4:8]), + binary.LittleEndian.Uint32(key[8:12]), + binary.LittleEndian.Uint32(key[12:16]), + binary.LittleEndian.Uint32(key[16:20]), + binary.LittleEndian.Uint32(key[20:24]), + binary.LittleEndian.Uint32(key[24:28]), + binary.LittleEndian.Uint32(key[28:32]), + }, &[4]uint32{ + binary.LittleEndian.Uint32(nonce[0:4]), + binary.LittleEndian.Uint32(nonce[4:8]), + binary.LittleEndian.Uint32(nonce[8:12]), + binary.LittleEndian.Uint32(nonce[12:16]), + }) + for i := 0; i < 8; i++ { + want := binary.LittleEndian.Uint32(expected[i*4 : (i+1)*4]) + if got := result[i]; got != want { + t.Errorf("word %d incorrect: want 0x%x, got 0x%x", i, want, got) + } + } +} diff --git a/vendor/golang.org/x/crypto/internal/chacha20/vectors_test.go b/vendor/golang.org/x/crypto/internal/chacha20/vectors_test.go new file mode 100644 index 00000000..b441fbd1 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/vectors_test.go @@ -0,0 +1,578 @@ +// 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 chacha20 + +// Test vectors for ChaCha20 implementations. + +type testCase struct { + length int + nonce [3]uint32 + key [8]uint32 + input string + output string +} + +var testVectors = [...]testCase{ + { + length: 0, + nonce: [3]uint32{0x94d13317, 0x6b6a2b3, 0x3ffe0036}, + key: [8]uint32{0x9da8a3b6, 0x3abf4ae6, 0xa2f19cae, 0x1068c707, 0x72e4801e, 0xce165d92, 0x61e7028f, 0x82ac3d57}, + input: "", + output: "", + }, + { + length: 5, + nonce: [3]uint32{0x469fadd, 0xee3fcc1e, 0x45cf77b0}, + key: [8]uint32{0x3477e02b, 0x45bf809f, 0x27f4a1fa, 0xdb901de8, 0xd8a190dc, 0x1d2c21d4, 0x87bdf2ac, 0xdfbf0000}, + input: "23dbad0780", + output: "415a3e498d", + }, + { + length: 9, + nonce: [3]uint32{0x512a6b49, 0x8df9af6d, 0x5336a2a5}, + key: [8]uint32{0xe9124c25, 0x4fd1a373, 0x7945f7bb, 0xeed5f064, 0x29c4185d, 0x3c9acf13, 0x4c94a367, 0x7c2c2c53}, + input: "f518831fab69c054a6", + output: "cfe40f63f81391484b", + }, + { + length: 12, + nonce: [3]uint32{0xca697a9e, 0x6b2f6717, 0xb7859220}, + key: [8]uint32{0xfc825020, 0x5ca4410b, 0x7d5285d0, 0x160a1c9d, 0x15470b41, 0x3634742a, 0xe64aa7fa, 0xca0be67a}, + input: "805fad1d62951537aeed9859", + output: "47bd303f93c3ce04bce44710", + }, + { + length: 14, + nonce: [3]uint32{0xcded3db3, 0x35770a7f, 0x6aede9b}, + key: [8]uint32{0x44632def, 0xa5e420a7, 0xfc12a8f, 0x63b79a15, 0x337de314, 0xb82fbf16, 0x3104bc57, 0x677c9227}, + input: "f4e8a7577affb841cf48392cf5df", + output: "f445c0fb7e3d5bfdab47090ddee6", + }, + { + length: 15, + nonce: [3]uint32{0x348a50b1, 0x4acc9280, 0x8d6014ce}, + key: [8]uint32{0x34bd31a8, 0x2808f47e, 0x9d8b19f9, 0x4df59683, 0x31584348, 0x34a74a45, 0xde174a2, 0x29d4c7dc}, + input: "1179b71ec4dc34bd812f742b5a0b27", + output: "cc7f80f333c647d6e592e4f7ecc834", + }, + { + length: 20, + nonce: [3]uint32{0xc8754703, 0x9188c521, 0xac8ce8a6}, + key: [8]uint32{0xe93c79ed, 0xce89162b, 0x116a8366, 0xecdc657f, 0x5bc81d98, 0xff5d2f52, 0x171f3ebb, 0x50773f2f}, + input: "7bd94943d55392d0311c413ac755ce0347872ba3", + output: "c43665de15136af232675d9d5dbbeca77f3c542a", + }, + { + length: 21, + nonce: [3]uint32{0x9a8655cb, 0x6e9d6ea5, 0x5dad705e}, + key: [8]uint32{0x3542d5b3, 0x1f7bfd8f, 0x1038abf8, 0x7214e8ec, 0xedd05693, 0x60e663bd, 0xe8e5d506, 0xeea923a2}, + input: "1505f669acc5ad9aaa0e993ba8c24e744d13655e1f", + output: "26cad1ccf4cf4c49b267ab7be10bc2ffa3ba66bc86", + }, + { + length: 25, + nonce: [3]uint32{0x3f202ca4, 0x63fc86, 0x7260a10e}, + key: [8]uint32{0xe28ab1d6, 0xe83b3d47, 0x671271ca, 0xb977bcff, 0xa2f64476, 0x311d79b4, 0x180d91d0, 0xec1a6e0c}, + input: "20070523ddb4ebf0d5f20fd95aacf47fb269ebadda6879638a", + output: "5ce972624cb2b7e7c28f5b865ba08c887911b4f5e361830a4b", + }, + { + length: 31, + nonce: [3]uint32{0xcf8671ea, 0x8d72df2f, 0x8b5a538a}, + key: [8]uint32{0xe46ca2bb, 0xd06ab5ef, 0xb0e2966b, 0x54dd0c2d, 0x8815d89a, 0x426c30a9, 0x15b0f1e, 0x254bae75}, + input: "d10f8050c1186f92e26f351db36490d82ea677498562d8d4f487a0a4058adf", + output: "f30c11bc553b2baf6870760d735680897c9fee168f976b2a33ef395fdbd4fc", + }, + { + length: 34, + nonce: [3]uint32{0xd1be983a, 0xf5aa389, 0xfa26c7e1}, + key: [8]uint32{0x795c6da7, 0x8cb1aadc, 0xa042359a, 0x95ea2e27, 0x128253c4, 0xaabc592f, 0x391e810, 0xf641d971}, + input: "e88dc380b7d45a4a762c34f310199587867516fac4a2634022b96a9f862e17714d17", + output: "aac98ba3821399e55a5eab5862f7f1bfc63637d700125878c2b17151f306c9aec80e", + }, + { + length: 34, + nonce: [3]uint32{0x98f5f4b8, 0x3f181d73, 0x5bf4572e}, + key: [8]uint32{0xa86f8cf7, 0x8db41a2b, 0xe0e03156, 0x3dad8a59, 0xb3e4d1ba, 0x75f6fb38, 0xdb94709d, 0xc3db34f3}, + input: "b0fcf0a731e2902787309697db2384e1cda07b60002c95355a4e261fb601f034b2b3", + output: "b6c8c40ddda029a70a21c25f724cc90c43f6edc407055683572a9f5e9690a1d571bb", + }, + { + length: 40, + nonce: [3]uint32{0x7289ae18, 0x7ebe7e50, 0x7d819176}, + key: [8]uint32{0x336c07a0, 0x4a2ea22b, 0xa8872f46, 0xa47b5e28, 0xbe645e3f, 0x371c6591, 0xd2dc237a, 0x92c59580}, + input: "cf9ec6fa3f0a67488adb5598a48ed916729a1e416d206f9675dfa9fd6585793f274f363bbca348b3", + output: "bb7ed8a199aa329dcd18736ce705804ffae8c3e2ba341ae907f94f4672d57175df25d28e16962fd6", + }, + { + length: 47, + nonce: [3]uint32{0xfd3181de, 0x8b193e26, 0xbebc799}, + key: [8]uint32{0x781a4c2e, 0x27ab55e2, 0x814aaf43, 0xa0bab01, 0x9de62ce0, 0x472b03d2, 0xdfee18e8, 0x8b855b93}, + input: "be9a8211d68642310724eda3dd02f63fcc03a101d9564b0ecee6f4ecececcb0099bb26aabee46b1a2c0416b4ac269e", + output: "3152f317cf3626e26d02cff9392619ea02e22115b6d43d6dd2e1177c6bb3cb71c4a90c3d13b63c43e03605ec98d9a1", + }, + { + length: 51, + nonce: [3]uint32{0x27b02ff6, 0xa510613e, 0x218b22d8}, + key: [8]uint32{0x62fc7732, 0xcef06cf4, 0xa4f45ed5, 0x2f96654f, 0x9f2b956e, 0x42b572f4, 0x5bb59c86, 0x35e4784f}, + input: "495343a257250f8970f791f493b89d10edba89806b88aaaeb3b5aefd078ba7b765746164bce653f5e6c096dd8499fb76d97d77", + output: "62c01f426581551b5b16e8b1a3a23c86bcdd189ab695dbea4bf811a14741e6ebbb0261ef8ae47778a6be7e0ef11697b891412c", + }, + { + length: 52, + nonce: [3]uint32{0x9db97a63, 0xff50248, 0xf2b6df56}, + key: [8]uint32{0x2b657a8f, 0xfe67575d, 0xaa56d261, 0x30179a97, 0xaefcfff1, 0x9b8eb698, 0x1efe3756, 0xb4ea450c}, + input: "e37fbbd3fe37ce5a99d18e5dcb0dafe7adf8b596528708f7d310569ab44c251377f7363a390c653965e0cb8dd217464b3d8f79c1", + output: "b07d4c56fb83a49e8d9fc992e1230bb5086fecbd828cdbc7353f61b1a3cec0baf9c5bf67c9da06b49469a999ba3b37916ec125be", + }, + { + length: 56, + nonce: [3]uint32{0xc1dfec38, 0x7d7503d3, 0x9a3e3c66}, + key: [8]uint32{0x8614d8e7, 0xde9b0413, 0x2a48b4fa, 0xcbbde744, 0xad5ddc5e, 0x9144d83e, 0x74d9d617, 0x230bdb45}, + input: "9efab614388a7d99102bcc901e3623d31fd9dd9d3c3338d086f69c13e7aa8653f9ce76e722e5a6a8cbbbee067a6cb9c59aa9b4b4c518bbed", + output: "829d9fe74b7a4b3aeb04580b41d38a156ffbebba5d49ad55d1b0370f25abcd41221304941ad8e0d5095e15fbd839295bf1e7a509a807c005", + }, + { + length: 63, + nonce: [3]uint32{0xc7e2521c, 0x795499b4, 0xc7946cd7}, + key: [8]uint32{0x53fce774, 0x9a4b53bf, 0x5f614134, 0xa3c39414, 0xa8a07c72, 0x93242311, 0x43aeec99, 0x216deb5a}, + input: "03b5d7ab4bd8c9a4f47ec122cbeb595bd1a0d58de3bb3dcc66c4e288f29622d6863e846fdfb27a90740feb03a4761c6017250bc0f129cc65d19680ab9d6970", + output: "83db55d9eb441a909268311da67d432c732ad6bda0a0dae710d1bce040b91269deb558a68ced4aa5760ca0b9c5efc84e725f297bdbdadbc368bea4e20261c5", + }, + { + length: 66, + nonce: [3]uint32{0x1d41f0a1, 0x7c3b7778, 0x6991eea5}, + key: [8]uint32{0x1f213e39, 0x56261d14, 0x15fc7c2c, 0x21feccc5, 0xa95684c5, 0x26600506, 0xdadcc06b, 0xf2c810b0}, + input: "2f4da518578a2a82c8c855155645838ca431cdf35d9f8562f256746150580ca1c74f79b3e9ae78224573da8b47a4b3cc63fbed8d4e831a6b4d796c124d87c78a66e5", + output: "6fc086ded3d1d5566577ccd9971e713c1126ec52d3894f09ab701116c7b5abda959cbb207f4468eb7b6a6b7e1b6d2bc6047f337499d63522f256ee751b91f84f70b6", + }, + { + length: 72, + nonce: [3]uint32{0x749f022c, 0xa021dab0, 0x648c2252}, + key: [8]uint32{0xa1ace7b0, 0x567a0ea1, 0x52af13b9, 0xcba30c08, 0xe07a6d74, 0x5c3bca39, 0x85b2ac07, 0x3b5afc0}, + input: "55739a1738b4a4028021b21549e2661b050e3d830ad9a56f57bfcaca3e0f72051b9ca92411840061083e5e45124d8425061ab26c632ac7852118411ac80026da946357c630f27225", + output: "8051bf98f8f2617e159ba205a9342ab700973dd045e09321805eed89e419f37f3211c5aa82666b9a097270babc26d3bfe0c990fe245ae982a31f23cfbf6156b5c8cfb77f340e2bf5", + }, + { + length: 74, + nonce: [3]uint32{0x23c16ba8, 0x9fd1cd4e, 0xcb224ecb}, + key: [8]uint32{0xb694404a, 0x86b5f198, 0x10fd1bff, 0x13a84e54, 0xab21e509, 0x7443d764, 0x931b3f1, 0x686e87f2}, + input: "7ffd8d5970fdee613eeae531d1c673fd379d64b0b6bfedd010433b080b561038f7f266fa7e15d7d8e10d23f21b9d7724bb200b0f58b9250483e784f4a6555d09c234e8d1c549ebb76a8e", + output: "c173617e36ea20ce04c490803b2098bd4f1ff4b31fdca1c51c6475ade83892c5f12731652d5774631d55ae2938617a5e9462bb6083328a23a4fba52de50ca9075586f2efc22aae56e3a8", + }, + { + length: 81, + nonce: [3]uint32{0xd65f6f29, 0xf3f76219, 0x9a033c9e}, + key: [8]uint32{0xeba017c4, 0x69e0421a, 0x449e2317, 0x29858a11, 0xd0c8523a, 0xa8b0c9a2, 0xab2ca84, 0xaf011a45}, + input: "7a5766097562361cfaeac5b8a6175e1ceeeda30aec5e354df4302e7700ea48c505da9fdc57874da879480ecfea9c6c8904f330cbac5e27f296b33b667fea483348f031bef761d0b8e318a8132caa7a5943", + output: "5e9fbf427c4f0fcf44db3180ea47d923f52bee933a985543622eff70e2b3f5c673be8e05cd7acbcadd8593da454c60d5f19131e61730a73b9c0f87e3921ee5a591a086446b2a0fadd8a4bc7b49a8e83764", + }, + { + length: 88, + nonce: [3]uint32{0xc70ee56e, 0xe58ec41, 0xafd96f61}, + key: [8]uint32{0x172af2bb, 0x9085d27c, 0x8ca2c44d, 0x8aa148da, 0x290c88b0, 0x88187439, 0x18d54781, 0x633f2cce}, + input: "0777c02a2900052d9b79f38387d2c234108a2ad066cbf7df6ea6acc5a3f86b3d6156abb5b18ad4ecf79e171383a1897e64a95ecdbba6aa3f1c7c12fe31283629ff547cb113a826cb348a7c10507cc645fa2eb97b5f22e44d", + output: "368c90db3464ba488340b1960e9f75d2c3b5b392bdd5622ff70e85e6d00b1e6a996ba3978ce64f8f2b5a9a90576c8f32b908233e15d2f443cccc98af87745c93c8056603407a3fb37ce0c1f8ab6384cc37c69c98bfecf337", + }, + { + length: 92, + nonce: [3]uint32{0x3006da79, 0x2748051d, 0x72c17cdc}, + key: [8]uint32{0x60cdb7e8, 0xcecbe928, 0xe19b7ab9, 0x30d61537, 0xa0fbc199, 0x897738bf, 0xdd7705a9, 0x3e5c1763}, + input: "cf2dccbcfd781c030376f9019d841ca701cb54a1791f50f50bee0c2bf178182603a4712b5916eebd5001595c3f48283f1ba097ce2e7bf94f2b7fa957ce776e14a7a570093be2de386ececbd6525e72c5970c3e7d35974b8f0b831fbc", + output: "7c92b8c75e6eb8675229660cedcb10334965a7737cde7336512d9eff846c670d1fa8f8a427ea4f43e66be609466711fd241ccff7d3f049bda3a2394e5aa2108abc80e859611dbd3c7ba2d044a3ececa4980dd65e823dd110fea7a548", + }, + { + length: 96, + nonce: [3]uint32{0xfc0fb1ee, 0x414cc60a, 0x4144bd67}, + key: [8]uint32{0x103291c6, 0x822b03b6, 0xd29ab548, 0xc88f3efe, 0x6936056a, 0x28aaa61f, 0xa0df7858, 0xdaa23519}, + input: "e08a8949a1bfd6a8c1186b431b6ad59b106ae5552821db69b66dc03fbc4a2b970dcf9c7da4f5082572bc978f8ee27c554c8884b5a450b36d70453348cd6cac9b80c9900cf98a4088803f564bb1281d24507b2f61ba737c8145c71b50eb0f6dfc", + output: "73d043acf9dcd758c7299bd1fd1f4100d61ff77d339e279bfbe6f9233b0d9afa24992a9c1c7a19545d469fdfb369c201322f6fe8c633fcdcffef31032bfb41b9fb55506e301d049fd447d61f974a713debeaed886f486a98efd3d6c3f25fbb30", + }, + { + length: 103, + nonce: [3]uint32{0xc2030c57, 0x1e3b59e1, 0x607ede1a}, + key: [8]uint32{0xd1bac2b5, 0x56a94583, 0x628b479b, 0x3056a51e, 0x69bf8f8f, 0x2df1e03d, 0x4b9d48d2, 0x7df5c379}, + input: "a0c302120111f00c99cff7d839cdf43207a7e2f73d5dd888daa00d84254db0e621a72493480420c9c61ce1cfc54188ff525bb7a0e6c1cd298f598973a1de9fd2d79a21401588775b0adbe261ba4e4f79a894d1bd5835b5924d09ba32ef03cb4bc0bd6eb4ee4274", + output: "bc714bd7d8399beedc238f7ddeb0b99d94ad6bf8bf54548a3e4b90a76aa5673c91db6482591e8ff9126e1412bce56d52a4c2d89f22c29858e24482f177abacef428d0ae1779f0ae0778c44f9f02fe474da93c35c615b5fad29eca697978891f426714441317f2b", + }, + { + length: 109, + nonce: [3]uint32{0xf44dc81f, 0xcf6e03e7, 0xf4966796}, + key: [8]uint32{0xd7b12f4, 0x683f4789, 0xc7828fb4, 0x820fc6a0, 0xc51231eb, 0xe46716d7, 0x4036ef93, 0x26afb96c}, + input: "ebce290c03c7cb65d053918ba2da0256dc700b337b8c124c43d5da4746888ca78387feea1a3a72c5e249d3d93a1907977dd4009699a15be5da2ca89c60e971c8df5d4553b61b710d92d3453dea595a0e45ae1e093f02ea70608b7b32f9c6aadc661a052f9b14c03ea0117a3192", + output: "cbb8c4ec827a1123c1141327c594d4a8b0b4a74b0008115bb9ec4275db3a8e5529a4f145551af29c473764cbaa0794b2d1eb1066f32a07fd39f5f3fe51498c46fba5310ae7c3664571d6a851e673ded3badc25e426f9c6038724779aa6d2d8ec3f54865f7df612e25575635ab5", + }, + { + length: 115, + nonce: [3]uint32{0x8d3e461b, 0x7e05c360, 0x3bbbafdd}, + key: [8]uint32{0xf9b917c9, 0x9af89bf7, 0x7decbbc9, 0xe7e5ea7b, 0x9b4aab55, 0x90eff6be, 0xa19b6d90, 0xb9f69b1a}, + input: "275c97de985aa265332065ccce437770b110737a77dea62137a5d6cb62e9cb8b504d34334a58a71aba153d9b86f21377467b2fafaf54829331bf2ce0009acb37842b7a4b5f152aab650a393153f1ed479abc21f7a6fe205b9852ff2f7f3a0e3bfe76ca9770efada4e29e06db0569a99d08648e", + output: "b225aa01d5c438d572deaea51ac12c0c694e0f9dc0ed2884a98e5e2943d52bb4692d7d8f12486de12d0559087e8c09e4f2d5b74e350838aa2bd36023032ccbcae56be75c6a17c59583d81a1fd60e305af5053ac89f753c9347f3040e48405232dc8428c49dcb3d9b899145f5b3bc955f34dbbe", + }, + { + length: 119, + nonce: [3]uint32{0x871f33f5, 0xe4fee3ba, 0xcb8c1e93}, + key: [8]uint32{0x33124903, 0x7e0287e5, 0xe9d6988f, 0x1962405f, 0x5f21c1b5, 0x2ac695e6, 0x46b200c9, 0x9fda98ba}, + input: "ceda15cfffd53ccebe31b5886facd863f6166e02ec65f46f54148860a5c2702e34fd204d881af6055952690cd1ffa8ba4d0e297cc165d981b371932adb935398c987baff335108c5e77f2e5dd5e1ca9a017bc376cbdbe3c0f45e079c212e8986b438444e79cd37927c1479f45c9e75b0076cc9f8679011", + output: "a3f1c3f885583b999c85cd118e2ababfa5a2de0c8eb28aacc161b1efee89d8de36ddeb584174c0e92011b8d667cb64009049976082072e6262933dbf7b14839805e1face375b7cbb54f9828ba1ed8aa55634ec5d72b6351feff4d77a3a22b34203b02e096f5e5f9ae9ad6a9dd16c57ce6d94dcc8873d18", + }, + { + length: 120, + nonce: [3]uint32{0xef553ce8, 0xdfe120ea, 0x9a047e3a}, + key: [8]uint32{0xbef479c1, 0x59554f8b, 0xbf97f089, 0x52316f1e, 0x141e428, 0xff26dc04, 0xe10c8f57, 0xa7568a59}, + input: "799bb2d634406753416b3a2b67513293a0b3496ef5b2d019758dedaaac2edd72502fc4a375b3f0d4237bc16b0e3d47e7ddc315c6aef3a23fcae2eb3a6083bc7ac4fd1b5bf0025cc1cb266b40234b77db762c747d3a7b27956cf3a4cf72320fb60c0d0713fa60b37a6cb5b21a599e79d0f06a5b7201aeb5d2", + output: "e84dfb3dbaac364085497aeabd197db852d3140c0c07f5f10e5c144c1fe26a50a9877649e88c6fe04283f4b7590a8d0d042ef577693f76f706e31c4979437590fe0ab03d89afb089d1be50ae173ea5458810372838eceac53bf4bac792735d8149e548efb432e236da92bf3168bbcf36f644c23efb478a4e", + }, + { + length: 123, + nonce: [3]uint32{0xd98124a0, 0x78cd80aa, 0x3dc55cfc}, + key: [8]uint32{0x2286e41, 0xf13e38e3, 0xf735476b, 0x33c44bfc, 0xd7978797, 0x4a9c4595, 0x6080413, 0x1299fdd8}, + input: "b2d060bd173955f44ee01b8bfcf0a6fad017c3517e4e8c8da728379f6d54471c955615e2b1effe4ce3d0139df225223c361be1cac416ade10a749c5da324563696dae8272577e44e8588cd5306bff0bfbdb32af3ac7cbc78be24b51baf4d5e47cf8f1d6b0a63ed9359da45c3e7297b2314028848f5816feab885e2", + output: "ffa4aa66dd5d39694ae64696bfa96f771accef68f195456ad815751e25c47ed4f27b436f1b3e3fcaa3e0d04133b53559c100cd633ced3d4321fc56225c85d2443727bce40434455aa4c1f3e6768c0fe58ad88b3a928313d41a7629f1ce874d2c8bcf822ebdaebfd9d95a31bb62daab5385eb8eefe026e8cbf1ff7a", + }, + { + length: 127, + nonce: [3]uint32{0x53106b0f, 0xdf11fd81, 0x69d1b6f3}, + key: [8]uint32{0x736b138, 0x55cde194, 0xf8273c1, 0xf7c268e6, 0x61362bd5, 0xbb3cb455, 0x44d3c9fc, 0x7d56d3fd}, + input: "4f0171d7309493a349530940feece3c6200693f9cff38924114d53f723d090fffa3c80731b5ca989d3e924d1fa14266632cb9ab879e1a36df22dc9f8d1dadea229db72fded0c42187c38b9fa263c20e5fb5b4aa80eb90e8616e36d9b8c613b371c402343823184ecad3532058a46cf9e7ea5a9ecad043ac3028cbcc3f36d32", + output: "88c773ff34b23e691e14018ba1b2bd48a4a6979b377eb0d68336ce6192dcd5177e6b4f1c4bea2df90af56b35fe2a1d6279d253c0194dcbca9bf136f92d69165b216e4c9d1ce6b3fbe40c71e32c3f4088de352732d0e2bad9c16fd0bb9bde3d6c30257ce063432d09f19da79d49aa7641124a6c9e3f09449e911edbae11a053", + }, + { + length: 130, + nonce: [3]uint32{0x5e90ffbd, 0xa898f173, 0x269f9a88}, + key: [8]uint32{0x5244e05f, 0xf9adbe9b, 0x9e9f54ac, 0x23460046, 0x6782cdea, 0xba982c96, 0xc721506b, 0xed10f7e3}, + input: "8f8d9e18d3212bd20b96d75c06d1a63622fd83d13f79d542e45996135368772ea81511302a0d87e246dd346314cfe019bae8a5c97f567f12d82aca98dfea397c6a47dd0c419f1c609d9c52dcfcbe7eee68b2635954206ed592b7081442ce9ce3187d10ccd41cc856fb924b011f817c676c9419f52a2938c7af5f76755a75eb065411", + output: "4e130c5df384b9c3c84aa38a744260735e93783da0337ade99f777e692c5ea276ac4cc65880b4ae9c3b96888760fdddb74bc2e2694bedf1ee6f14619c8015f951ba81b274b466e318d09defe80bdbed57bc213ac4631d2eb14c8e348181d60f6295ceee1e9231ae047830ef4778ff66146621b76974773b5d11c8e17a476450f46ef", + }, + { + length: 130, + nonce: [3]uint32{0x308e39e8, 0x9aa4f14f, 0xf511db96}, + key: [8]uint32{0x833b5219, 0x4b82e588, 0x4b2d652c, 0x7c8f6ed7, 0xfe4be863, 0x9d3a50e5, 0xb888099b, 0x9f8d1968}, + input: "30d2379dd3ceae612182576f9acf6de505ab5a9445fe1a86ae75c5c29429e11c50fd9ec657b29b173a3763b1e171b5a7da1803ba5d64fccb2d32cb7788be194dbca00c3c91774c4c4c8ede48c1027d7cc8b387101a4fe5e44a1d9693b2f627626025072806083aadbced91c9711a0171f52ffb8ed5596cf34130022398c8a1da99c7", + output: "b1e8da34ad0189038ee24673979b405ef73fdbdd6f376f800031d64005a4ebed51a37f2180571223848decbea6dd22b198ab9560d7edc047c5d69183dc69b5fca346911d25cb2a1a9f830dc6382ad0024e8c3eef3aa2d155abcfe43bff01956a5e20a862fbed5c5e8df8eed0601a120caac634b068314e221f175baa11ae29002bb9", + }, + { + length: 135, + nonce: [3]uint32{0xa5feca5a, 0x753ac1b4, 0xc5a46609}, + key: [8]uint32{0xabbf4859, 0x828d9bf6, 0xf7f7aa6d, 0x25208ca2, 0xd7a4c0ad, 0x2fdd3282, 0x2bfcb8c2, 0x8389d84b}, + input: "d9404ccdcc8ef128a1b1ace4f9f1669d274ec82aa914cac34b83ac00b236478fd6167e96ec658850c6c139eb0f6fc0dd7191ba9a39828032008f7f37eb9a8df9d6cdd54240e600efe7fc49a674000c5030d825b2c5c96d0f19b8ecdbf4eeb86d3e569c5e3131abc7d6359dd4255284ccacf150d42e7a899536d51ee6db329654a4581c5ac6e419", + output: "c5534b5fb40b4834300e9577a9d87440c5272263d06e6aee84aa92cdf5d1b033145d336f26e5fe55c09a7e75753af93d0786dfc1cb435e86c67bd3ec8e766d0801b99e68691e2c3c3ffec539cf62e68285ea9027daa2716cd6f97e8eb7b9e266357a25eb2d4839a829508a6b7228f2832b3cd998f77597ae530430e6e4ecb53eb9efe456863a04", + }, + { + length: 135, + nonce: [3]uint32{0x12aa5846, 0x88604f6c, 0xc10d9585}, + key: [8]uint32{0x1491ccd6, 0x602f559d, 0xd4080c06, 0x202fabd, 0xffd3f4f8, 0xbf144c17, 0x88bf3f3c, 0x8083375}, + input: "231765f832927461f338aceb0f4cf51fd8469348c69c549c1dec7333d4aa4968c1ed58b65ab3fe3d0562600a2b076d56fd9ef91f589752e0455dd1d2e614cacfc0d757a11a4a2264bd38f23d3cca108632201b4f6c3b06477467726dde0c2f3aee01d66d788247663f1d0e66b044da9393ede27b9905b44115b067914961bdade85a2eca2844e1", + output: "1dd35f3f774f66d88cb7c2b23820ee078a093d0d85f86c4f103d869f93e2dbdd8a7cb8f101084fe1d7281a71754ec9aac5eb4fca8c365b24ed80e695caace1a8781a5a225938b50b8be96d0499752fdabd4f50d0b6ce396c6e2ca45308d1f2cc5a2a2361a8ca7a334e6ee62d466d74a1b0bf5b352f4ef6d8f8c589b733748bd3d7cda593243fab", + }, + { + length: 140, + nonce: [3]uint32{0x1c9d70f0, 0xa088a367, 0x4ec24d2b}, + key: [8]uint32{0x494e9775, 0xd07a852, 0xaf8af24a, 0xc65b825c, 0xc5e06780, 0x17fbbace, 0x651d71b5, 0xf548d8ef}, + input: "e46841f12d98aeb7710b9162d342895a971b0e3a499886bbb6aa74dc744a28d89a54542b628acdc2f693cb7c03f73fc3b74069bc3f2d000a145fb8a806cdc7d6fa971da09a33b92851cc3d1f6f5646d7fa2b1d564876feefeb63b6e66dba1c0b86ca345235bb822e0f93132346840d2a3d6eb1b541178ea51affc7b31f8da02732cc4e5bcb5d8683ae0a91c9", + output: "1dcbfd0bb2b905656c52bd7b1bcdad9b4d434ae9ac221a0d3a316115cdd4a463fa9b3444d2612a4e277d0dcd881fa6e80e59e5a54e35e1a14747aed31edf4ac24214f9d9c329ebe2157620b64efaded9976549bc4aa100d5c15be3f85f700f8a21dfe77590dfee2de9a23cc1ed1e44f32ebf68ca289b097bc13b42802dc7c75309c4afc25b5741839f7db3d5", + }, + { + length: 144, + nonce: [3]uint32{0x23067b8b, 0x5b276c6d, 0xaeca6c60}, + key: [8]uint32{0x29d64488, 0x893a2973, 0x32e3b4ef, 0x2af3d5d4, 0x95ec01b, 0xc805b64c, 0x884e8b7d, 0x798d7062}, + input: "e98e4a9550bdd29e4106f0cc8669dcc646a69438408e9a72c7cdb9b9d437b5f7a13fcb197629541c55bca1f8972a80cd1c1f591a0e24f977cdeb84763eab2648e42286e6473ea95e3a6a43b07a32b6a6cd80fe007ba0cf7f5ac7e651431f5e72690ec52a7134f9757daf0d8eff6b831a229db4ab8288f6bbf81e16fedebe621fd1737c8792cfd15fb3040f4f6a4cbc1e", + output: "5c69cf522c058790a3bc38979e172b60e71f7896d362d754edc1668d4f388b3fc0acdf40786d2f34886e107a142b1e724b9b9b171cb0e38fd78b35f8ac5269d74296c39c9f8628d848f57af9d8525a33f19021db2b9c64ba113171ebb3882075019ec7e77b51ce80b063ed41d48dad481d9536c030002a75d15c1c10ce0ec3ff17bc483f8416055a99b53035f4b6ea60", + }, + { + length: 148, + nonce: [3]uint32{0x2b079658, 0xbdf5da85, 0x8a75450d}, + key: [8]uint32{0x49c9eaa3, 0x62048819, 0x9baacfa5, 0x3870addc, 0x5c682e1, 0xf4f9fff3, 0xa3848e4b, 0xac1ebc1}, + input: "ce0f0d900dd0d31749d08631ec59f216a1391f66a73bae81d3b0e2919a461bc9a14d6a01b827e3bcb55bbccf27c1ed574157e6becd5cf47181a73c9d3e865ab48a20551027e560e965876b0e1a256bfa5cb5179bf54bd8ec65e5570e374b853b37bf4b3ef1ec612d288ebc19275fa88da9419e012f957f9b6a7e375b3377db0eb3619c731aebfeb0930772b4020d3a3e90723e72", + output: "b06981b57fe184091ef9f8ccf522a5bcdb59bf9a68a3ddb817fdd999a6ecf81053a602141cf1b17017bae592b6b6e64756631a2b29a9e1b4f877c8b2ae30f71bc921e4f34b6f9cd8e587c57a30245f80e95005d0f18f5114400785140e6743da352d921fb4a74632a9c40115ad7706263ac9b41a11609fa0c42fc00f8d60931976162598df63ebad9496dd8943d25a03fa47475c", + }, + { + length: 148, + nonce: [3]uint32{0x98e8ab8, 0x84d8e77b, 0xbb305841}, + key: [8]uint32{0x46b5f93c, 0xc8b2778d, 0x2cc5278f, 0xd2a3904c, 0x6ce5d4f, 0xc4459e8, 0x4a35c30, 0x2feadc02}, + input: "eccfd66bdc691478f354b8423d6a3f20932a1f591d8e6cefa734975fb8ee6881b6dc92c0d1d5ed54fd1999efd7f11ac697a1f130587dd895eb498c9a8fc7d1714c385ec156ecae3bdea2a3462834245e724531d0fedda2b77693a53ed7354b758e875b23cfc83219a091fb2076e7a88cd77f779ed96f8d81ffa3fe5059303ac706086494b9f2982f4f88a0c6fadc3748625004db", + output: "925529047d4177b72bf50905ba77e47608815522c1829b24046e439d5451901257903a5409fb910373167e8b7f4fdfa543a477608ddfc11bbd1efc138366961463b9915b302a346b795dd593f6fcf4fa73529b6fe83079552aabbe99474a72806f59688d826675fa7f6649b9f5307e5028853c9821b8c4a1a0fc4bfdc7c8c78b25aeaba2b5821d17b36317381a3bd578917d2504", + }, + { + length: 152, + nonce: [3]uint32{0x2e2a6e4a, 0x9a6d488a, 0xf9966cb6}, + key: [8]uint32{0x58903bff, 0xc2be173f, 0xe26128b5, 0xb6b6af53, 0x92f8eeb, 0x38cf3336, 0x7fdf90fb, 0x7ae24b37}, + input: "f0c7139c69413869bca980d7f192b2bc3f57e34ca4f26164e1a54a234e84e1aa285cc02cfbaef3dfba2dbb52a555ec1f6ef0e89d0b2f0bd1846e65b74444b5f003a7308965e67bed558689be2668ca10ca368fac072e0e4535a031af23b3c37c561e185872b86c9bceddb5c1199e43fb5f735384766d33710460b541b52d3f5b6c108c08e76724bcac7ad2d866a8bbeeea92a3d867660d2e", + output: "d2c16c7a242b493038203daec65960de384c030eb698ef6a53c36eabb7556cbfa4770eaa8bc0a2b385ad97495eeb1c03ff4e6efcb804aefa81c177dc62700a9eefe6e8dd10cff5d43a2f47463cab5eb1ee260c3826cac9bfa070f1e0435541a89ebd224d13cc43f8fff12f38091c2b3f2102d5c20d8b1c3ae4f129364bbe9f9ce2147dcf0639668ddb90dffe6a50f939f53fa7ba358e913f", + }, + { + length: 155, + nonce: [3]uint32{0x243e0198, 0x884448c, 0x9a31e760}, + key: [8]uint32{0x37e017bc, 0x9b1e2e90, 0x15679daa, 0xf94a23ee, 0xda86dfe, 0xc3eea84c, 0xdd199799, 0x6eeffb92}, + input: "7024974ebf3f66e25631c0699bcc057be0af06bc60d81a7131acaa620a998e15f385c4eaf51ff1e0a81ae5c6a7442d28a3cdc8aeb9701055e75d39ecac35f1e0ac9f9affb6f9197c0066bf39338a2286316e9d1bb7464398e411da1507c470d64f88d11d86d09e6958fa856583ace697f4ee4edc82618662cb3c5380cb4ce7f01c770aab3467d6367c409a83e447c36768a92fc78f9cbe5698c11e", + output: "ff56a3a6e3867588c753260b320c301ce80de8c406545fdd69025abc21ce7430cba6b4f4a08ad3d95dc09be50e67beeff20d1983a98b9cb544b91165f9a0a5b803a66c4e21bd3a10b463b7c1f565e66064f7019362290c77238d72b0ea1e264c0939d76799843439b9f09e220982eb1dc075d449412f838709428a6b8975db25163c58f40bf320514abf7a685150d37a98bac8b34ccb5245edb551", + }, + { + length: 160, + nonce: [3]uint32{0xd24e866d, 0xc59d25d8, 0xfcf623f1}, + key: [8]uint32{0x5f32cca0, 0x4167cac5, 0xc04943ee, 0x507fa1ec, 0xad8fdfc0, 0x6266fa2d, 0x22f05341, 0x8074143e}, + input: "8d79329cf647e966fde65a57fc959223c745801c55312046b791671773cca0af4cd48ead1f316eba0da44aa5d18025eced0c9ed97abaabb24570d89b5b00c179dca15dbae89c0b12bb9e67028e3ae4d6065041b76e508706bec36517a135554d8e6ef7cf3b613cbf894bec65d4dc4e8cb5ca8734ad397238e1e5f528fa11181a57dc71cc3d8c29f3aba45f746b1e8c7faace119c9ba23a05fffd9022c6c85260", + output: "60aea840869f7be6fcc5584b87f43d7ba91ed2d246a8f0a58e82c5153772a9561bdf08e31a0a974f8a057b04a238feb014403cd5ffe9cf231db292199198271f9793c9202387f0835a1e1dc24f85dd86cb34608923783fd38226244a2dd745071b27d49cbffebea80d9dacad1578c09852406aa15250de58d6d09cf50c3fcfff3313fac92c8dad5cb0a61ccc02c91cecee3f628e30c666698edecf81831e55ec", + }, + { + length: 167, + nonce: [3]uint32{0x30b61047, 0x810cf901, 0x4d681524}, + key: [8]uint32{0xe51476d0, 0xdf98008d, 0x59dfe69e, 0xdb39166, 0x6c1e4a4a, 0xfb76165e, 0x5180f185, 0x7359fb35}, + input: "85484293a843d2d80b72924b7972dfa97cbe5b8c6bcc096f4d5b38956eb3f13f47b02b0f759ea37014ecdecfb55f2707ef6d7e81fd4973c92b0043eac160aaf90a4f32b83067b708a08b48db7c5900d87e4f2f62b932cf0981de72b4feea50a5eb00e39429c374698cbe5b86cf3e1fc313a6156a1559f73c5bac146ceaaaf3ccf81917c3fdd0b639d57cf19ab5bc98295fff3c779242f8be486ba348bd757ba920ca6579be2156", + output: "bb1650260ef2e86d96d39170f355411b6561082dcc763df0e018fdea8f10e9dc48489fb7a075f7f84260aecc10abcfadbc6e1cd26924b25dedb1cc887ada49bb4e3e02006bdd39098ef404c1c320fb3b294ded3e82b3920c8798727badfb0d63853138c29cf1ebf1759423a1457b3d2c252acf0d1cde8165f01c0b2266297e688ff03756d1b06cb79a2cc3ba649d161b8d9ef1f8fb792bd823c4eabb7fb799393f4106ab324d98", + }, + { + length: 172, + nonce: [3]uint32{0x42020cbe, 0xad62af90, 0x29e53cd}, + key: [8]uint32{0xabad2095, 0x601ec477, 0x3bc923a1, 0x1edede1a, 0x33612355, 0x285b4858, 0xd3fd6714, 0xe0f4bcc3}, + input: "a2fc6e1b5281a4e0330eecd1ab4c41670570423173255979953142b78733b2910fa5540e8294208df6ae4f18672d5ac65acf851bcd394e1932db13c81b21e6f165e5538aff862e46126c650bbe055e54b31c78f2f0221d2631d66ef6d3f4c5ae25eada043b74d8770e2c29799c0954d8ccbd17766b79e6e94e88f478db3566a20cb890846917591a07738328d5c05f7ed4695a82607660f1239661faa9af0368aeb89726f13c2aaecf0deaf7", + output: "d8fe402a641c388522842385de98be60f87d922c318215947d4b7562d4ca1e2dbc7ee86494e65fb0bfddfdebdb2ae6469312f95b32c722b2720d64bb8d7cc3dd82f9055b1d89f05b77984f91f94ba4ac79c5129cd7c91cc751b0defc3f2799518e372d27aa683f1e7bbd4f55414c48fe8a3a37ac1f179a1a329cda775aec0d31d75a5a38addb1de67c06bddbedf4c8d87abc18c9f9dd072d457ea29ad4dfb109ce7e99a4a82fbe330b0afbb5", + }, + { + length: 176, + nonce: [3]uint32{0xa8021c8f, 0x667a02c4, 0x7a68b693}, + key: [8]uint32{0xece401c8, 0xfa805a47, 0x6d572fca, 0x9c1c780c, 0x647545e5, 0xd7ef4c11, 0x91dc1e46, 0xba2a694e}, + input: "480387bc6d2bbc9e4ced2448d9ec39a4f27abe8cfb46752d773552ad7808a794058962b49e005fef4e403e6a391d1d3f59025eeb5fb8fbbe920f5361862c205d430eac613cd66108f2f2f0bd4d95a8f6ca7bd1f917eaeb388be87d8b7084a2eb98c575034578edf1b3dafff051a59313873a7be78908599e7e1c442d883d3fd3d26787eb7467eed3a3fb2d40046a4460d5d14215565606bcf8b6270af8500e3504d6d27dacf45bace32214472d525fdc", + output: "ab81a9c28358dfe12e35a21e96f5f4190afb59214f3cf310c092ab273c63cd73a783d080c7d4db2faccd70d1180b954cd700c0a56b086691e2c2cd735c88e765e2266cd9ebe1830d63df4b34e2611a8abeeca9c8c4fac71135dafb1cb3569540ed1362ddeb744ed62f6fd21de87b836ec2980f165c02506e0c316ae3cf3d18a862954d9781f726ecc1723af4a730ccc6d6de82553450a52499acb58fb2008969401c45b2f20e12b58f308db1d199b4ff", + }, + { + length: 176, + nonce: [3]uint32{0x414e687c, 0xc6fc69c2, 0xd3ca12d3}, + key: [8]uint32{0x1b51cca, 0xbc8455af, 0x3f904842, 0x6042b452, 0xcd4dd164, 0xda83f3f0, 0xff04b972, 0xf972dd0e}, + input: "b274e61059f3215173ae226e30a92ee4b4f8a3da95f2e768e3fac2e54ddac92c200c525f190403a6ef9d13c0661c6a7e52ed14c73b821c9680f1f29711f28a6f3163cf762742ed9474dbea51ff94503a5a404adbbdfbf4c6041e57cb14ea90945dc6cb095a52a1c57c69c5f62ac1a91cd8784b925666335bbfee331820b5f7470bc566f8bbb303366aafe75d77c4df5de2649ed55b2e5e514c3cb9f632b567594a0cf02ec6089a950dbe00554ee4dfb9", + output: "a0969730d48ee881792a3927b2f5d279aba9f2ed01e6b31b92d0e1fb8ba7f35a236d838e0ce5f8654957167de864f324c870864b4e7450a6050cd4950aa35e5a1a34a595e88dd6f6396300aff285de369691b6e0e894106dc5b31525e4539c1e56df3ceedbbab1e85da8c0914e816270a4bae3af294b04a3ea6e9ef7e2aab4da5f5370df2706b5e3f000d88179ac756deaa652a1cc85e80ad9622f1bf91a2776262eb7289846d44f7f8192e763cb37aa", + }, + { + length: 183, + nonce: [3]uint32{0xdd315c1d, 0x2335da98, 0xe0a0da0f}, + key: [8]uint32{0x6419c7d6, 0xd340f42, 0x7af2f4b8, 0x3536cf42, 0x2f68c6fb, 0xac9d855f, 0x7c4d490, 0x9711b1b1}, + input: "ee849039c6cd972dc943d2a4468844d130c0150276f4e0889047e2300c3ecc6792c4527bfe9437dad877eb986e6b1aa9b867d1798c9d314243f0a87ec9ee5b601c2554876c87cbf50df3334a077c4152f8b8fef4a2d301ddbfa90c887ece757c3eb6c4fc1e0212d6b5a8bb038acaec28cba064c9b34f5364cb7f0fc2ac4ef2c7ddde0f5ba17014459eaa78f08a46a01882ebf7c6e409dadda250bb899dc8b3b70e160bbcb4412a9963b174d0fc6bc16383a46ffaacb6e0", + output: "3e272ded9c0a5cebe7cf17ac03f69eb20f62996e047501b6cc3c8691ddb2780ea72c21a81888bfea96e4373a412c55ca95648390de740102d661143043baec3976230e024477d134b8504a223c36a215b34164c9e9e1fa99a49fdc56f2f04ea525a6b82997d9bbc95c4b5baeab4dec50061efb7c1a757887acb8b47b142e0a2e61885a2c14c4642d83d718a0546b90699adc545a48129603862a1c89d8e665cde54b3ba487754db6d6f5acf6a4b95693cc569577a2dc48", + }, + { + length: 185, + nonce: [3]uint32{0xebb44f7c, 0xaf14c7dd, 0x4543cd7a}, + key: [8]uint32{0xce71977, 0x99790e86, 0x6510d6dc, 0x37968ae7, 0x2917fb9a, 0x19ef25f, 0xd282d085, 0x6128d043}, + input: "0992396a6f29b861dd0bc256e1d1b7dce88435733506a6aa20c62e43afa542d1c46e28b2e6d8e2eacb7c08db05e356fe404684b0e3a9849596db82eb788aa09258c28eb19e9838f757425b4edef12deeca56e30cf030272e325d4246d6e083219b2f965124963ca91f066d47bf5a8282a011a78b0155aa70038259a4a59135f241fd2f88c908b9f4eef7b7df0f3a1c16a52c009b522f89dabd52601bbf6e3ce68732e1a6d444469480f06da218786cf6c9666362e7a7f7be12", + output: "545c05a84b5a4fffd1dd623c8f2b11443818560bdb0c26dadd3b694d4790d294b99059f4127b7cca122c4000954d745af96094ff4623f60db33e994bb6903263d775f48d7047427b3a498c2ecde65bd37bcb8ee7e240a1e08c884c0079cab518f4e1c38ba5ea547f4da83b7c6036e4259bee91c42e8fae895df07781cc166f1d50e1550a88ee0244bb2950070714dd80a891aa8a9f0580a67a35cb44609b82a5cc7235f16deea2c4f3667f2c2b33e8eeef944e1abdc25e48fa", + }, + { + length: 187, + nonce: [3]uint32{0x35cb7190, 0x212e9a86, 0xbc423ce4}, + key: [8]uint32{0xfa19cede, 0x576ae8f2, 0x58055dab, 0x91b3355d, 0x69d2501a, 0x736323c2, 0x266c1385, 0x134f4557}, + input: "3b9efcbbb607fad5e9f1263dad014cc5c2617d439fcd980408f4f9a93acb1a33d1c3a22f38c037e4603dfbbfb5571bc08c4a1958cbbf510e3e4dd19007fe15fad7808369149a9c4db7ca0496f7a600a6f2454ee1cffd5a68d45c270e4b53ac9b77f33a1ffbb1804244f57d2b05b8036fe2cda9efead3d4eff074ea5c07128e0b354a4a11ffa179163933bc6bd10d200804cc93b64575746e94e975f990bddcc8a4335e99e2459fbe9bc0e004ffcd6cac52f48ef55cc0637a75c1dc", + output: "631ba7301e33236da2477506ea98d3b732447389e849b68e1f09bd5fd814f40dc3247a1012fa654f08e3dda0c104ee2dff12ecf5cb018644de50d70dfb6c8cc1f5f552e5f1e50466bbb538ad6b98fd37f33fe615c326efc9cc97899b829b007f91569fa9b28ce0076c53daedf9cc0f838e22cf1125b86a6a2c2eb4a45dadea45ad00fb4f054e7d6b09c13ab1dd5328debfbf4f1b70af2b8a5b1d02df8a87d7661473e0c180ba4c815f14db87c5bdc15f11a29d8e0ce3d747d5dcd4", + }, + { + length: 191, + nonce: [3]uint32{0xccc941ac, 0xdba45b02, 0xab0d7ad6}, + key: [8]uint32{0x9b750752, 0xa627090a, 0x967c95f0, 0xf8ff2c3f, 0x69beb97e, 0xa30b99c1, 0xadddc83, 0x443f9baf}, + input: "f28a71efd95e963e5e0bc0fcf04d8768ce93cb55dc73c32e6496022e214596314b7f843f5c7b136a371c2776a0bfbdd534dccbe7f55e9d3d3b5e938f2d7e74393e4caf6c38fa4b05c948e31dc6a9126817fa3d7892c478f75ab9f6ab85c0e12091bd06e89c7d3ca8d9dcdd4c21fead3d769a253919c2c72dd068474ea322b7e71cafa31684e05a63e179e6432fb70661792cc626a5060cec9e506b35d9286f15dc53cc220b1826314eec337dd8e7af688e5950b2316c30516620569ea65aab", + output: "1bcea54b1bf4e6e17f87e0d16388abe49b988b9c785b31f67f49f2ca4011ecd2ad5283d52ef707dd3b803e73a17663b5bfa9027710e045a0da4237f77a725cf92792b178575456de731b2971718937dd0e9ea12558c3fa06e80bbf769e9799f7470db5b91476d6175f1a6d8e974fd505854c1230b252bb892a318e6d0c24dcc9ecb4861769cd746abab58805bc41c6086a6d22b951fba57b00c5b78f6dcb2831715b9d4d788b11c06086f1d6e6279cd130bc752218d7836abc77d255a9e7a1", + }, + { + length: 198, + nonce: [3]uint32{0x987e7c58, 0xcc839a94, 0x30952e60}, + key: [8]uint32{0xe34a286f, 0x4adcd996, 0x97168712, 0xa82dde8, 0x14249e5, 0x5e82810b, 0xb4a445e8, 0x9579adb0}, + input: "c1d1ede73bd89b7c3d4ea43b7d49c065a99f789c57452670d1f92f04f2e26f4f5325c825f545016c854f2db2b3448f3dc00afe37c547d0740223515de57fd7a0861b00acfb39931dc9b1681035d69702183e4b9c6559fb8196acbf80b45e8cc5348b638c6d12cea11f6ef3cc370073c5467d0e077d2fb75e6bf89cea9e93e5cf9612862219ca743ef1696783140d833cd2147d8821a33310e3a49360cb26e393b3fee6dba08fcda38d1b7e2310ec1f715e3d8fa0c6b5e291eea07c25afd5c82759a834a89cc5", + output: "11a8493cdc495c179f0d29c2b4672997205a9080f596ee3c80d79b55162b1c875ac18eb94bf2a9e05b08024f524a1e9665912394a330c593d23260e6bdf87620c10a48f678693196fb744c49054182fba667c601e7b7ebf0f068e8d69ba004b804fda616a4a0d5350e1a3bd424b8266462be282308219c578569aefc1ccd09ecdf5da283356c9e524e14e69d25b0e19643dab26f54373a7272b43755c3f1ddaee6c5fb9e8e093110c41697e95f73a68c75454e050239197c9fbd8cec76698bd11894ebf6e2b2", + }, + { + length: 204, + nonce: [3]uint32{0x851f025a, 0xe6f3c800, 0x85ae7530}, + key: [8]uint32{0x2d0dbe47, 0xda05e465, 0x42f6b3b2, 0x7026e79e, 0x9e446680, 0x691df976, 0xf7b23da2, 0xbb3421fa}, + input: "37b2dc4b6a5203d3a753d2aeffcdaed5a7c1741ed04d755dd6325902128f63b6981f93c8cc540f678987f0ddb13aae6965abb975a565f0769528e2bc8c6c19d66b8934f2a39f1234f5a5e16f8f0e47789cd3042ca24d7e1d4ddb9f69d6a96e4fd648673a3a7e988a0730229512382caaded327b6bbbbd00a35df681aca21b186bc7ac3356d50889bbf891839a22bb85db4c00bfa43717b26699c485892eb5e16d1034b08d3afa61f3b5f798af502bba33d7281f2f1942b18fb733ca983244e57963615a43b64184f00a5e220", + output: "b68c7a2a1c8d8c8a03fc33495199c432726b9a1500bc5b0f8034ce32c3e3a78c42c1078e087665bd93c72a41df6bfa4e5beb63e3d3226aeeba686128229a584fab0c8c074a65cef417ad06ab1565675a41cf06bb0fb38f51204eccccb75edd724cdd16b1d65a272f939c01508f0385ca55ac68a0e145806317cc12e6848b1124943a6b2d99a8c92083fc5f31ab2e7354db3f8f2d783dbf1cfec9c54f8bfcb93d6f28ef66f18f19b0fab8836458e9b09bee742ba936cb2b747dd9dcf97ca7f6c82bf0af6f1b433592d65143fe", + }, + { + length: 210, + nonce: [3]uint32{0xaebfd97f, 0xf583442d, 0x15ab2f1f}, + key: [8]uint32{0xd3d1cf9b, 0xe43187e6, 0x5071a757, 0x412a83b4, 0x3f27716f, 0x17fdc488, 0x271f77ed, 0x6c4bb056}, + input: "68c2c5612912b5f994172720130dff092ee85a2c1395111efa64d5a281ca864d3db9600e685854d81c6de7e8747b92fb7c4c2efa829d3d4c0c9fc9d689e2e5c84c9eae8ba4ab536fb6c7523124b9e9f2997f0b36e05fb16163d6952eee066dd22fb7585925ffded0204cc76818bcead0d1f8095ca2cf9cd1ddcd0361b9c9451940e14332dac4e870e8b2af57f8c55996447e2a8c9d548255fe3ed6c08aedaf05bb599743ecb0df8655152bbb162a52e3f21bea51cb8bf29f6df8525eb1aa9f2dd73cd3d99f4cca31f90c05316a146aab2b5b", + output: "d0ae327fa3c4d6270a2750b1125145bdeef8ab5d0a11662c25372e56f368c82c6f5fc99115a06a5968f22ffe1e4c3034c231614dd6304e6853090c5940b4d1f7905ef4588356d16d903199186167fec57e3d5ce72c900fe1330a389200ed61eec0bdc3672554f1588ec342961bf4be874139b95df66431178d1d10b178e11fcbd26963ff589d5d5faf301b7774a56bbfa836112a6ea9c3026ebdd051085f9131132c2700674bef6e6c2c5b96aace94eb2ba6c0e0aef0eefa88995e742ca51ac50af83683b801b7c2c5af4880e2b344cc5564", + }, + { + length: 216, + nonce: [3]uint32{0xf9e973b8, 0x2485a6a7, 0x2ea7dee6}, + key: [8]uint32{0x96edef11, 0x8cf57f26, 0xb6e3a83c, 0x9ef434c6, 0x4607ea48, 0xace87e4d, 0xa0d87475, 0x3a9c9458}, + input: "fed3d1efa309c8b50cb9da02b95167f3b77c76e0f213490a404f049270a9c105158160357b7922e6be78bc014053360534add61c2052265d9d1985022af6c2327cf2d565e9cef25a13202577948c01edc22337dc4c45defe6adbfb36385b2766e4fa7e9059b23754b1bad52e42fce76c87782918c5911f57a9394a565620d4b2d46716aa6b2ba73e9c4001298c77bfdca6e9f7df8c20807fa71278bd11d6c318ed323584978ad345c9d383b9186db3bd9cec6d128f43ff89998f315dd07fa56e2230c89d803c1c000a1b749107a3159a54398dac37487d9a", + output: "6a95fba06be8147a269599bccda0ce8f5c693398a83738512e972808ec2f25bc72402d4bcd1bc808cc7772b6e863b0e49d1d70c58fcf4fcaa442215eeb3a4648ade085177b4e7a0b0e2198f0acf5465c97bd63f93781db3f0b9a0a184c3e06a76c4793a13923f83b2242b62511c2edff00b5304584cbe317c538de23785d2504fae8faabee81c5315298186ce3dcbf63370d1ccd9efec718cbc90b3d2e0b0b6aefb3a9b31e4311f8f518be22fdc2b0f00e79a283701c53f6936dd63734ecb24480d5365d1a81392498faf9a1ddee577007acc5f8c87895be", + }, + { + length: 217, + nonce: [3]uint32{0xe3bd4c44, 0xa3b75a31, 0xfe92010f}, + key: [8]uint32{0xdd05ab8b, 0x5ac7cd1, 0xb8113720, 0x53524706, 0x8e0ceea1, 0x52eb23e7, 0x1c85730b, 0xb33914d5}, + input: "d776bee5625d29a2ebf6fec4df94d2b9ac62e8e7c56704fd38a87ee932b787cbc555621535e76ea30183cb0ee30604f485b541f45feb8c01b9750d37fded5cdffbbc34fb90fdc9c7c7ddf949a1d50b796f1ea5db437238c7fb83c4b22c9e491f75b33d84746f1cd10bfda56851b8514ff0ded0adfd5092a66a85202d06bd967485d06a2c56011110da74bf40b6e59f61b0273164744da02ce2b285d5c3f03aee79eea4d4503e517177692ed3bb035071d77fc1b95c97a4d6cc0d41462ae4a357edf478d457c4805fa586515614697e647e19271091d5734d90", + output: "60e9b2dd15da511770162345251edfb15cea929fb79285a42f6c616dfde6befc77f252e653b2d7902a403032fc4ce4934620931a2ec952a8d0f14bf1c0b65cc287b23c2300999ed993446eb416749bf0c9c7dfe60181903e5d78a92d85e7a46b5e1f824c6004d851810b0875ec7b4083e7d861aabdd251b255b3f1fd1ee64619a17d97fde45c5704ab1ef28242d607d9501709a3ac28ee7d91a3aac00cd7f27eb9e7feaf7279962b9d3468bb4367e8e725ecf168a2e1af0b0dc5ca3f5a205b8a7a2aae6534edd224efa2cf1a9cd113b372577decaaf83c1afd", + }, + { + length: 218, + nonce: [3]uint32{0xcdabfd50, 0xd10d5b99, 0x9e160a85}, + key: [8]uint32{0x8231a4e9, 0x89f33c8b, 0xf96b11b, 0x853cae9d, 0xf6624a33, 0xee9523ee, 0x28bb7853, 0x688ac6f8}, + input: "4f57848ff5398e61bcafd4d4609bcd616ef109c0f5aa826c84f0e5055d475c6a3a90f978a38d0bd773df153179465ab6402b2c03a4bf43de1f7516eb8626d057ae1ab455316dd87f7636b15762a9e46a332645648b707b139e609b377165207bb501b8bccfa05f1bf0084631c648279afdf51c26798899777812de520f6a6f0d3c7f3ef866982f5d57f9c8d81c9a4eabb036651e8055a43c23a7f558b893dd66d8534bf8d179d8aa7d9e8987cfdaaa7b5a9381ba9c79d5c1161b1bdbd30defdd304ee07f19b7ba829a0d5b40a04b42edd6407b68399caac69069", + output: "e096cc68956ed16d2dea1154a259e01647913eeea488be0b54bd1816c781a35e161772ae1f7a26b82e864ade297a51cc9be518641b2e5f195b557ec6fc183e4e5c1fc01d84fe6ca75e5b073af8339427569b1b8ee7fcff0ffa5e7e6237987c40deec0abf091c06a3b28469c8f955fc72e4f3727557f78e8606123e0639dff782e954d55e236448f4223ff6301accda9f8fa6cd43a8d6381e5dde61851a5aec0f23aeca7262659bc793ce71fa7992f80e44611ae080b7d36066e5c75c30851306f0af514591d4d5034ecdf0d6c704bfdf85473f86141c9eb59377", + }, + { + length: 219, + nonce: [3]uint32{0x67de323f, 0xa0442ac9, 0x9d77b1d9}, + key: [8]uint32{0xca8d33d4, 0x834349d9, 0x5e68d581, 0x99a7c30e, 0xdc7f6038, 0x697e8b63, 0x284c2ece, 0xee3e3bfa}, + input: "046a61c0f09dcbf3e3af52fab8bbcded365092fad817b66ed8ca6603b649780ed812af0150adbc8b988c43a6ada564a70df677661aff7b9f380d62977d8180d2506c63637c0585dcef6fe3f7a2cf3bbb7b3d0df7769f04bf0f2e3af9439ab7615c304b32055aea0fc060890beb34fa9f90084814b6ed7363b400dfc52ee87925c5b4a14a98e3b50c7f65adc48c89ddd6414626c5e0bdefabab85c4a0e012243e682d4931be413af62fd7123ab7e7774fcae7e423bf1d3a31d036195437e9ea8f38aa40182daa9aacf3c9f3d90cc0050977c6065c9a46bcca6ba745", + output: "cd5a6a263e3ee50dda0e34c614b94c3ec1b14b99a2f4095a6b5715fdfc3449fcdf8a09d1ae02d4c52e5e638f1ee87a4a629f99f15a23dd06718792f24285f5a415e40f698752c697ee81f2f9248da1506ce04a7f489f8e2b02e6834671a2da79acc1cdfb78ea01822d09a1c4a87ffa44e56c4f85f97507044cf946ccb6a2e06e2917bac013f608d75ee78fa422a5efc9c569226bf7068d4705fde3a9fad2030256db0acf9a1d12666e0acf9f5346ad62e5af4c01a008d67ab1224b3e98278d073116ff966cdc779fb3aff985ec9411a3eefa042d71dd4ae5b15d5e", + }, + { + length: 221, + nonce: [3]uint32{0xa36a3d5a, 0x1747a05f, 0x5440eb4}, + key: [8]uint32{0x2d701ee6, 0x143d5a1a, 0xbb67b9ab, 0xabc88ccc, 0x20baad8f, 0x6507e48b, 0xdb1e1b39, 0x9e521d80}, + input: "af516216f74a6344cbe458cbba820f7e25c0b10aa84b790da2ee6317e059171076d7246c2878be83fc00c200d546c007f849e4c163d52c7b0da31beff4abff481be3266b92e668cf4dd1c84d9d7b3e5191dcd6ddb51d17d337621046e83e9ac035fccfb239648bc3c6fd340fbb50707e5a33b3ef439d292192d0e4bc727690c61450e5a28789e5ea50e746bc66d039493e080fb70e9ae06d89004cb71de8178941c422f1e9862492fc9149a4864ff52b1277b9f5a63c2f16e9adb5263cf65a034a62ebb0f1a385d2681c87a35f1c45670b4edef1c68fe9544fcf411d95", + output: "b22ffd8f0e549bd3e0206d7f01ff222f92d39b41cf995a331d5ef0cf5c24bcc3ddb36e64d351b5755400246fe4989b5f912e18daa46cdd33e52dafbd2872f16e94220b56315d72c1dbb1525fd34831d7202970c11711ff36de3fc479407c34fef0aea86e172f9beb0f393194355b9dd59625639f4a6bf72ba571c229f2fb053c1114e82793deb2dfe8232f1a327949689d2fb2820662dcd2a39a2546c7df12b3ff7e87e58c74badf568cddebd3c558f0f7874c834c4b8aa988653f138ec79620f5e3ed737690928a30f981dca9f2920ac7307607063b40f87c204de47c", + }, + { + length: 223, + nonce: [3]uint32{0xb92be022, 0x1e1257c7, 0xad7c01e}, + key: [8]uint32{0xca1dbb9c, 0xaadb9504, 0x77b8a95c, 0xc50deb5e, 0x2dbc0fb8, 0x9e654bc2, 0x94d8925a, 0xfe9cfb66}, + input: "a3d70bdb509f10bb28a8caab96db61652467cf4d8e608ee365699d6148d4e84d5d93bdabe29aa4f0bc8ee155f0b1fb73293c5293929eaacdd070e770c7cccfb2de120b0c3811abeeddaf77b7214a375ca67d618a5d169bb274a477421d71a651cfb9370bcf7e0d38f913754c11002089cf6cd6a8de1c8a937fb216591d57b37efdf3797f280773950f7eddeb9c3385c8315ff5ff581c64610a86ada7ff6a1657e262df94892dff9fdfb6e958d101f4c26296470c138dc4e1ca4bb565b3ff877a7f78b3d11d64b7c24e27ba6f6b06f6e368f5ac218cd5d11b815ab0987678eb", + output: "646314264896a6e25601e536f6e783d465b2ead1e0be4422bc9cc8eacabae4a749ad533eb28091be8397328dcfb34c92006bbda930ab070ed7b806095bb1c8f476350e7b08ffbd4d7d6055c8defaa8deff9d54f5215c2d7db27ce09e08f5d87a859145ea3126e2a01882921c3fddef3985bd451bca44063258390aec8ec725b07d064314fe43a9c83e9287b47616dfefbf539b82da209aa08a6d3176b7e3b4be4a17d44e581280a684e4a64414649bfcea82b541729f8178b580e8b972a89f5b8c4f9b68205e9396d8ae5e81873b61da074080fd44c52d50fb0880ee9c35da", + }, + { + length: 224, + nonce: [3]uint32{0x5091927, 0x661c75ba, 0xc23dad}, + key: [8]uint32{0x2e00499d, 0xafdc63db, 0xc3c62efb, 0xb4157a19, 0x84ce8b13, 0x85326279, 0x2ee71e9d, 0x318721e4}, + input: "f48b5ae62f9968baa9ba0754276cd8e9dcfa8a88e4571856d483ee857b1e7bc98b4732e81f1b4421a3bf05ab9020d56c573474b2a2ac4a2daf0a7e0c3a692a097e746d12507ba6c47bec1d91d4c7cfc8993c6700c65a0e5f11b1ccd07a04eac41f59b15b085c1e2a38b7d3be9eb7d08984782753ae23acdafbd01ae0065ab9c6d2a2d157c1fc9c49c2444f2e5f9b0f0bbfb055cc04e29b2658b85d414b448a5b62d32af9a1e115d3d396387d4bb97ba656a9202f868b32353cc05f15ae46cbe983d47b78ba73d2578a94d149e2c64a48d0c1a04fc68baf34c24b641ea0b7a800", + output: "b9af1016275eaff9905356292944168c3fe5fdffd9e4494eb33d539b34546680936c664420769204e91ead32c2bb33a8b4868b563174d1a46108b9dfe6d9ac6cc1e975f9662c8473b14950cbc9bc2c08de19d5d0653bb460bea37b4c20a9ab118a9550bfeb1b4892a3ff774e8efe3656adcdf48239f96e844d242525ee9f9559f6a469e920dcb3eaa283a0f31f5dfac3c4fac7befa586ac31bd17f8406f5c4379ba8c3e03a6992a1915afa526d5ed8cc7d5a2605423ece9f4a44f0c41d6dc35a5d2085916ca8cabd85ac257421eb78d73451f69aaedeb4ec57840231436654ce", + }, + { + length: 227, + nonce: [3]uint32{0x5d6d997c, 0x9d623987, 0x5742de36}, + key: [8]uint32{0x57b2a5ea, 0xc5bdd68b, 0x99c7b0c6, 0x26aea960, 0xba5c75f1, 0xa904cf6b, 0x685031de, 0xa0f0e99}, + input: "b39101601efa2ecdf41878b0fd920a3005ce709e4ec2970abb76e32c232ea21069f81b246eda75aace7555ce8ae203455d3723e684bd671389300e353eec0d2f499d10654fafda2e7a69bfca7198eb172249167ca8864b5d5f58d28723090ec86e251a1bac0346d52fd81f06e0c05429e0b2b895588290b7d00878a4da3378eb6c7e61487de2b318fedf68fa7ad7c88ee746827c1f60d98c7716f3f9695c5ffd4670f71a0fa78a1fb554ba482c5de83feaed7c65fc71acc9f541342eb8f7622b12bb2cfa222fa2ddd8b3ed210ce442275afa3132c8a0e17dd504ecbc92525c118952be", + output: "50eb5b21c179a03b9a822f0075906a3ce4acc32486139f92635c7d834f69071d5a6dc0e15ed06a5cee37147071d59641d140a82ad5815b954e7f28e080c3dbbeaf13943d7b7c66d49d51ba1132eeadd4cb7a7e7d726d08d95f1578d55519f267f753f3e16ff39504a87b2286d8bfba0fe6bc28887b466bf276453a82cdd0abbbbf08db0e1c26c317d50ad9b8dc09cd621bc566d362024e8404739df6468869d2125c58b25d70e392f5e75924c4341be81c263915bb514ad436fb24c2c67450e84f6d1b72d1a02a3310c07a7814d930264fdbbf5ddca7067e18e8a44faa87169b7f2e35", + }, + { + length: 233, + nonce: [3]uint32{0x75bca707, 0x89f6d1f4, 0x2a6f657a}, + key: [8]uint32{0x949f42cc, 0x2b5d3c48, 0xfe0be473, 0x17ac92aa, 0xbdc9d9dd, 0x74f9df26, 0x26487508, 0x7c7b41a2}, + input: "0a42f63b975ad0e12a1e32615813dfd6f79e53ce011e2a2f0534dd054689f8df73a8326fecfd517ff7fe530d78081af66c3a8c7c189eb9d9efed1e5577b5512d42ef1fe273f670ce380c64bc62e217a7e410a8ed89998344e29301e4e053a3a3cf7e71587fd056a6bd976f16e157476a06997dfaaff32172dd84190570621f2221420c0a0ea607ea756e9792c8c0e7157c95b89c9490e20b750ee85e4c27c9b8f409e848ec90afcad33342010bb9808358afbcb3d9b094127c38c243a204e76899677079758e7cbada9a5c18363449eebc07bab516a16372722403a046df85c7dd2ffc804c54d38aab", + output: "87a47bcaa1c1eb8e55151011c4f39af4b9e108a55a7124cdcf66d0dee727306e6971f783b038bd6b215f530cdbb53e17975742ec304fdb3792a88b674504396978c6a5e4a9c87a7c3ca430d61165c1a3f6162eeaf38c93e18b6ccb6a595ad428cdc98efef8f84463eed757a72ffd827b71c0579fcc1f4baa11812be2bc5a2a95df8e41d04b33343df09ce628c367d1f88488f7a2787f013c8e76f0b9257cee777ec4adc6df8c5790e41ea02da85142b777a0d4e7c7157a48118046935f8888b5352d1750bf00b92843027a349cf5685e8a2a2efde16dcf5e1c1ed8c779bb38cabfb42ec4dd87d58273", + }, + { + length: 234, + nonce: [3]uint32{0x5003a4f7, 0x40bd8cde, 0xfe35fb25}, + key: [8]uint32{0x576e49d9, 0xe84e9df, 0x9f227a3, 0x437c9de0, 0xc46ac8de, 0x1a6a2d2b, 0x42ab7684, 0x4253fbb6}, + input: "abeff48fa082dfe78cac33636c421991b0d94c3bc9e5bd6d22763601a55201fa47b09ce60cb959ba107020213c28ae31d54923d1e74ab1d9ddc2762b2d23d8c6961d81068230884a39682fa4b30676ffec19319362c075df0b879a0f083a67b23597bf95c4bb997fae4736479cb8a9c00520ba2f6e5962d54c313c576180d17779ff239ad60f1f1373627770d50a1c49718b2b2e536846299e052f8c1a5d3079e91cb1b8eac4661daac32d73b3b99e2051f8f694a61d1e9d3935f802921a4d979b6ade453cf30d73a4a498a6a2c5395c60fcf271d50b4967ac12b0d7bf818c2679d552e9b3b963f9f789", + output: "a0d11e732984ad575570ed51031b8ac2d7b4c536f7e85f6fce9ef5d2b946cefe2ee009227d6747c7d133ba69609f4a1e2253d0eb59d1f930611e0c26a7c0cf2d2ce7ccea6e079eadf2eb1acf0463d90fb4b3269faae3febfc88cb9fb0873d8b74894506199394c8e44a96e6b479bd3e045749cce1c3f57243abdb37e67084eb573cd820c6cee424227019592a027e9da8f7b8997bfb292627a986f83c8fb8d156a91a12a8b52659cf9272924631745ed3a2453a4c2d87a167faa9104e799c715ed597bcb66949ab15dae29a86ba147507e8d8af66e96c09c53caa053ad3b79d9ed3c0c6c00169eaec3a3", + }, + { + length: 237, + nonce: [3]uint32{0xc6ae48ce, 0x26f0906f, 0xfd8ab8bf}, + key: [8]uint32{0x42b82c50, 0x7f519e0d, 0xcbb95098, 0x6f75e532, 0xe2c9f61b, 0x5a4af942, 0x2679777b, 0x6a8e1c9c}, + input: "a77b7a5870335b9145fd2e08ec898ba2f158fda16e8a2661a7a416857b6ba6937b4843ecaa79d3635d28383af80290842de9ca0bb621ee22b7fd6bf379922741e812b1739c33dd6923d0607826fc84d46bbdbd1fe9d1255f56a167779a560a6eed1b9c9579b8f771147df467e67a070d9e9ce8ad92dc0543d1c28216c1dec82614ac5e853ed49b6abac7eb3426ef0c749febce2ca4e589d06ccfc8f9f622ede388282d69ceb2fd5122ba024b7a194da9dffc7acb481eabfcd127e9b854be1da727483452a83d1ca14238a496db89958afd7140dd057773ea9a1eee412875b552d464ba0fab31239c752d7dd3d9", + output: "b330c33a511d9809436ab0c4b84253eeda63b095d5e8dc74803de5f070444a0256d21d6c1cf82054a231b43648c3547aa37919b32cfd9893e265b55545be6d7cd11d3f238ef66c3c278fcccb7dd0dc59f57750562cb28da05d86ee30265ff6a3991a466ba7e6208c56fc8862e19ac332e5fb3cbcc84e83a6205dee61a71acd363a3c9de96d54070a69860c152d4ceb9c4b4cc3b878547b6116699885654b11f888dc3c23483a4b24fbe27c52545c06dd80ab7223d4578ab89bff5f9cbf5d55b19611a5251031df5da5060a1f198226c638ab5e8ec5db459e9cd8210f64b2521a2329d79228cc484c5065ef8a1d", + }, + { + length: 244, + nonce: [3]uint32{0xea38678b, 0xc41eada, 0x3381147b}, + key: [8]uint32{0x268fc2ac, 0x21297e86, 0xdf9ef8cf, 0xd4b45234, 0x2a95c4f2, 0xcec36ce3, 0xd5fa38c9, 0x7dc43790}, + input: "322d634bc180458123e10d0509870b54e0f0a3a72a2bd9e9cf44324c7a1ca37dd6adf9db1fcc8dadabd881f91d47d93b58382802b42ee936802fac8612ea4dd9eca5f215935ea9ba6233b9c8bddba3385861de669d95c888c8977851cb305db577a4eb2360f362fa459d61ffc8fcaa1502905b073bd8e9567ac7cff8e5fb1002c55641a3af5fc47ac0131fae372f073e19721ffcce9821e0241d7fa67bfc499c8f100e050d39bd4d7cae4557d208629603ec4a007852762ec1905d0e81b873510fd334dedcd9c288eb8415db505913af06bea94d197ab627d58f6a9944f6c56247595fc54ae3f8604aa37c3466f74561131e11dc", + output: "edbfb1090987762f75eba2439d746cdbefe8605b8ebad59e075d28b54edfe48813ccae891f6ed655c5ab5211ba896fff0c8e09bd1554aad987dc53f355d0822e9b0f524a99a79c68a9f3b4e30506cd725b07be135e4540078be88dac64fc545c433837b96a924452f6b844291c4c3fb5f8cc94f06d9f19dad7fc945f093020e82ed19f9eb3ddff68b813629991d1a460e5455e1cb41cf23bb3d96fdb6b96581c3bf9ef72814406329bbbba5b835e7724c728cebe88efcd996dea71d0fd5c53e081c21ce8b3764738d693e390fbf8e0137a716760fc9cd2014cd9bf3fd706bc3464d1f15803606976e96b1077cda0a62921ff7c32", + }, + { + length: 250, + nonce: [3]uint32{0x883ac584, 0x8fb8e7d5, 0xdf07de66}, + key: [8]uint32{0xc7747e47, 0x853d88c6, 0xbf9aa631, 0x78f16480, 0x7c248080, 0x15ff973b, 0x31528a40, 0x629686e5}, + input: "e6b8a9012cdfd2041ab2b65b4e4f1442794fdf1c3685e6622ce70f80b9c2252ba6d9e6384d474a7622053d35df946a3b19408b3e1712da00525070279ce381359b542a9ad7c07750e393e0834593777352c1f7dbc84cc1a2b1eba787377d2cb1d08a7d20e1393d44022107acac5d765be37f9075af02e4bbf8e60ceb262aa34e2b870cc7adcf54329a667249cb4958393bff4f4333338cae45cbca419d59e605aa0cecb1241080339198b9b283e4201afc07360b8ae2a57b0b9b97167c315f03fd7a87a00ae73f91ca560a1505f3cdf04576b9aee5ea775f719916f1e1942ad5311c7f87153f8e62855ace3f34afb08d4d7c7f4fd2bf83e42f76", + output: "fc2673c80812d101bca7a2e0e105fa449550e695a016596f5c3cde11fb7dc518b94fdb74058e634546a726c37896110e1d1f9cdeccba1c89958041061ded8e8bc2751ec6dad76a305e70c57f9c81a5a65b5116390af4f7bf7053a03ec13f5d60a58cc5ba61f8c46ef6d2d291de490082dcfdf294aeb3a9414d64e4bd6497d4625acfa591627bfd98f0aec7e7def71515c09942db6911d73b96b4bd2d6df03bb729e945d71549d40e4bc401e1f73baf263a74280537692240638619f92645a5ade1eb8151191c7ff8bd715b3c1cd667e69745b806e16d46d9aa680a7367b8fb45a1598631cf3d44c1f5cfcd95bc8dafdb65a2083905a6937fcf21", + }, + { + length: 256, + nonce: [3]uint32{0x79cd7a62, 0xae619be, 0x7d96d236}, + key: [8]uint32{0x7dec8e64, 0x9f12b14, 0x6c70df2a, 0xeae0aa0d, 0x27b1ac14, 0x7a00d833, 0xe63c0aca, 0x189438e2}, + input: "0cfd93b195e37dd15dfae83132c24ed5bfce7fe6fad4064b213b2c31a39e39ddad2f977e904c9c5b055ed03db46fcdd845bbb6ff0ab5a8c92e89295b6801f36ae63eba61fba24a3858aeb36f2da226b23b24d7b2c7d2670f23a9a1b60db85c0ecee584bef1b00e42d10ca17432a74bbb220d88356d82c850da4c09dd5baf413caf8f9479e02a330065fb865489c0f59605d56146ec8434182345de2d15e2a1dceeeee2fe94871d41913f6788738947ed9849ca0ae985e3e19a97bee82b96feeddceb196c9b6012264661945981c279f43db9599a4ef01116f592478619690daa64387290484d21e8d2444751194e1f361fb37f04014a3c7e4b409e5c828d8990", + output: "0502848571d1472ff10bec06c1299fad23a2cb824d88bf91b5447c5139500bd837a2fddc629e4a964e84907c1e6740263f1fef4f5ed41062982c150d9e77a1047b7d86c0e191945e8db00ca3845a39560857fc9e0e4a394eea4ba80a689cb5714c4bab7124ffdbfa8bbb91c3eb3caa1621f49dba1eea3ebf1d547ee337f9085638a12317b86c11aa1525813445107038942fc519eebdc1b98d313ad822bf0b94a054259aa8cf1be4b3a68f974269729941747f9a23fa5d83453071b431dac62274c24f6a32248b0785ff90aad5840fadc89af0aef7553d9352cfb00d3999ffbe28cd9fde7854e95710f4532b8bf5011e518c93361e58d22a2302182e00e8bccd", + }, + { + length: 268, + nonce: [3]uint32{0xb7581e00, 0x9a1bba92, 0x64356674}, + key: [8]uint32{0xdc2c9fcd, 0x5e50de1a, 0x8546466b, 0xc1b49b21, 0x36a670cd, 0x2887f367, 0x2fbf4300, 0xf90a0374}, + input: "0d8d864010ce8df1c0179cf0236dce1c100f9c115eaa5294c24a2e1afa27f9d57ebc18f00482be0218d44262bd4db73002ff53c6388f5e333470aced2a42a73b376686c8d02e05ece27cdd8b1e3f675c715981f8b656d68d0e16227b529cf881d2433e4371fbcd933eaa72346e77e688ac80ee95324512c66a4c16338cf38c941b72c21c3d01e005a07c0eb436014fb1ee61806de7e96842ca3217ab8c7607d609dd2f637f9fda8a85cb0549f262c9e4a955c384319a6ad2b696e2593d7d174f5ddb98e2a8d5d12558c18ab67571e9a0202e91ce26d720cbe41a3a6a4f309296ca4d9d9a59a9043dd2e5a707ed7d5034023d5ea06ab14b39b7852e5c984848d5670c6f2f0b189c2a8a4a4bca", + output: "d2a5693c9d503a8821751d085a0837579233e65b691366e4a7464481d22800e786939349f721a815f28b4e47c8889f0814fb95d592d1185e45d6dbcac14ffa4f1d6c79194f2f7eb7323439d9607edf80f01e3a968b483eb93c01d9cb9d3625d21d66927e7aeedc1d9bd589560ed2b61cbed5ad0e0310c8ebe140c64c67d4909c010902d5386efa359ab60a9573493d3e5d8761cfd4023eba23de48372032d4673b5f6ad66cd0dfab02a73aa81f269ae88fcabb3ae9cb09f6bf60fd3575a3046bc6843f444e1e9fb9ff9b991620344fb99da68df09496b40f8b9dfc34e830a87f65710940603ebab554d36e8b4c9228bc9c26c07b828f34cdfdd40b161717236ba325e8c20bd018b324345e09", + }, + { + length: 305, + nonce: [3]uint32{0x2c641fcb, 0x5170c7e2, 0x62a23688}, + key: [8]uint32{0x5aed5915, 0xc5c4cc18, 0xf0e51574, 0x75d894c6, 0x1b7082d1, 0x5d2ea1db, 0x709fd24, 0xf5f69898}, + input: "07c50a69e168e388caf6f91471cf436886a3de58ef2c44795d94fba6538add8d414d84f3ef0ac9377fd5bed6aa6805a695f3a711025550bb6f014893c664e09bd05f4d3b850771991fc02f41c7353cd062156243b67fce9c1f0c21eb73087a5de0db0578923eb49bf87a583351e8441c7b121645bcb64ef5960fdca85af863dca7ebb56662e9707d541513bc91bf9b301431423b552e2c148e66ecfd48045ecb3a940dd65694d7fc8bf511e691b9cfd7547fe7bca6465b72ff9f1748723c4eb14f8bc1efb2fbc6726115c597a3881e0d5019335daf2e5ea8796c2a8b893ca798c4ef2639465505c4bd492bf7e934bb35be9b66c9f35730736c65fa4c1a2485378b9d71912cb924634a8e0db2802b75728818dc00fc28effdf1d8a05e4de4608bb6a78bb19c377d5ec77dca1b5ad38fded7", + output: "3dff5fde2ca24bf419e13cb7d12368e70449d41f2aa22e4b567f5cbdbcf3257975e44097deb180f2621ec36acf375dad3b7a19234b9856dc6c7842a7f86be00304b41a8c1662a02e8390346cbd0ff6be7bc1ceb821dbd805ab5c93c9c6ea5093249b5dc52081cbbbe1b326e831ef3c6c42fb791790086d1586f7daf031e70a71b54e9134f942e9ce229fc77980eb80c985ee0c5965eaba375d156f9b423b0615f4ca6fd77de28e28f35aba327e4f1b75725730155b7b4d6c5c264bf3d9dc9a16e7ededcc261add8c666278bac5cf0b3275d6d6678060eae30bbf2ce5f63e6a53a450b65aa0adbd1c90cf045f5ddd9700c2a99c80586c5244cf4c08035b6ff630c82cec3a4fcc83860e987898b42fe746939f8b37c814f8dab65de276e9784fb90f0751d3ba0826889e1e7e4fdbf8a90942", + }, + { + length: 430, + nonce: [3]uint32{0x99b172cc, 0x91056d0, 0x48057533}, + key: [8]uint32{0xe6cf398e, 0xc3c56066, 0xc5ff194c, 0xf6d2d8c4, 0x6d1d8908, 0x63e62065, 0xcca485cb, 0x1eb03dd6}, + input: "3ddcd3c00014747903c95e49f64258615455a0b26c5070a9532382a9bbd18eeb19c9fe1a902f5c6baf544c5938fc256d310a9332223dc3c54a6eb79a4b4091c3b01c798d2800418863f2865c1cd8add760e445588576d4a6c945e1d6d50dc913674daa4737ac94d84eb0ff57cda95df915989c75adc97c4e3c1c837c798a432ba4803a246bb274b032db77e5c1bb554a5342ef2e5d3ff7f102adb5d4e282ad800ccae83f68c4bfd3b6046786a8cfaa2b63c62d64c938189b1039ae1a81ce5c91530772cca0f4a3470ba68e4e0548a221eb4addf91554e603155a4592dc5c338aa0f75a8cc2822b318fbfba4a8f73fa08512132705dae792eed6b809c251d35cca60c476406d964187b63cd59333771e37367671d0ccb393f5b8bde77bebc133485ec5c66bdd631d98cdbee78a3cf435d2f824fa2f9e91e89af28b2e155df4fb04bbe4ce0b6162dcd8e81ee8d5922ebf9c957b26c343a0396d91f6287a4af9e11b7fbb5a5a5c1fcdb186365a20617d4ff5037b0bfa97b6213a6ebcf0b78b81c65737378787b255cba03d715fed4addc2c70c1fb4d3ab16f2bff287186c26a164dae2fe9dbe3c4a2e1617f01cae79f", + output: "ecea5fc18dc4aed23359cacb8f79a457512e0a27d9816f353e315519d2b2faf74d14ae8ae5e227b203823998a47a050c363a807f45f610942fed4518b8091b88dff8b2af8fb6552eb654c85d2b6a918bcf56fb898392941d983b1afd867ef840e12313059ed3e4d217498dd511563a939c3c536fbbf8e019deed29262f0a655fc680b15939475e0cee0ce2e8bab5834f7354b93e2e0958a5bc608fab369b6aee3c9d73a6898e402484eac7300150517bbd137bf55762897696a3dc4be74b0c141755ac8f2f6e59f707b1690c451a774c46bbe195d826a6784f8d807b78f8ebc343ecacf37cb9b1b2fdbff6a1237b5098853d783e77515c419894c2628f8b5117042294ee2ed58a33746f9e79b13fdfaa25a75fc95340a89076e786e0ecad7de437a9a3fb3092146d255005b22895310b1252a3e34572cf74665b97f4adc30dd0f34e3216c7757953a4b618a775bbe68f9e0922d75afc80a1379aaf1745f2263afb6f0b37553d9c984f1ef781ea75b1980c559c77565c83f3e0bd7a3cd7cdb594658beb7e5eb940633dbc6ae2f50383beea676cb6c814b17b1d73dd133f544da88ab371415889ead21803c1ffe3f2", + }, + { + length: 449, + nonce: [3]uint32{0x2adb4a6d, 0x33d00c1c, 0x10a0193c}, + key: [8]uint32{0x8bd707df, 0x70212019, 0xdb685581, 0x9cdbd1a3, 0x7db9ff1a, 0x1af119ee, 0xb1d8c0ff, 0x3c4a22cb}, + input: "93ce72a518ae892e00c271a08ead720cc4a32b676016612b5bf2b45d9ae9a27da52e664dbbdf709d9a69ba0506e2c988bb5a587400bca8ae4773bf1f315a8f383826741bfd36afeae5219796f5ce34b229cac71c066988dbcae2cbcfcdbb49efcf335380519669aaf3058e9df7f364bfd66c84703d3faaf8747442bdd35ac98acdc719011d27beba39f62eab8656060df02fab7039223f2a96caac8649bc34da45f6f224f928d69c18b281a9b3065f376858c9fd10f26658ae21f5166a50fe9a0d20739402eec84f5240ee05e61268f34408089e264e7006a59bb63eeaa629ba72603e65718d48e94e244e7b39d21d85848d5f6f417631f3876f51b76b6c264356d7d7b1b27bbac78316c5167b689eff236078cf9e2e4626a4ae8bedeecbcaf6883e2e6e9304969b4fc7a4280dcdc5196267e9bb980e225fcbf7a9b2f7098f7f5c9edd06f50c8791edaf387ff3e85ff7bee1f61e4660fddd4eaf5ab0320508e3ccaa9823ae5a71faa86bd76e16d862d83ed57bf6a13de046a3095a74a10c4da952b3c9b8fbde36048537f76eef631a83d55d3a13096e48f02b96a5a8da74c287a9164ce03ddf2f868e9ca3119ec41f0233792e64086c903eb9247dbae80e923eae", + output: "bcf49d62dcd1cff9dc37d7096df0c39031e64ccaeea3830fa485edb71b7fcf2ec709a4b327ef9c7d4ea2b35f113a8485d4c236e06b3baccee30e79c6c08739fe5fbed59db30479b56dfbe584a5d79b169b200430ed27072137e940a34170606b31f22095f2151b4d9b901f6337f991a23e4c8997a1ebf5105361fdade1c889b8dc9565e3b33e0bd608c39d725becbb60da8a797186fe0986736112da3d09906442364d6e253e5b27fd5ad72e877c120ea7a11d42b19948f0df5ddabf9cf661c5ce14b81adc2a95b6b0009ece48922b6a2b6efffdf961be8f8ec1b51ad7cfc5c1bca371f42cdac2389cbddcdc5373b6507cdf3ffc7bfb7e81487a778fcf380b934f7326b131cb568bbaa14c8f427920aa78cc0b323d6ea65260022113e2febfb93dcfce791ab6a18489e9b38de281169f1cd3b35eee0a57ed30533d7411a7e50641a78d2e80db1f872398e4ae49938b8d5aa930c0c0da2182bd176e3df56ab90af3e46cdb862cfc12070bc3bd62d6b0387e4eee66d90c50972427b34acaf2baff9d8a76002a20f43c22ac93686defc68b98b7b707d78d0e7265aabadde32507a67f425cbd16c22a426d56b9892bac3a73dd2d2c03efdb22ecc6483f8d1ca67fc7d5", + }, + { + length: 487, + nonce: [3]uint32{0xecf15215, 0x45e31add, 0x56499d31}, + key: [8]uint32{0xf5988496, 0x49bcc2df, 0x7b4ba3c3, 0x5d5138be, 0xd6cb466b, 0xe98c82f8, 0x147d3f27, 0xc82389f0}, + input: "f72bec13b0f0b6f2317118f14c2a0d8e963b1bd49ae7584e710dbde75bb1e30c79281847cb822a5f3ae4fa56825e511212f17f0d293cfe80f872e6992d304e9283d08ce65ceeacb003b36a862c91282a22536e0b9c19953512a1bf9e20d3e7a8f1a2dff45dec0b9b04c592e88a7814540cf636a024d10008463d0b3aafbc4c9359889149433ef173124866aa6f53526ef3b3f2c630860ecdd08ffd9fc050e95da512cc87f812f9391085cdec5cc87258b8560806a52336d612da7ab05e0f60566b950904aa27c975a48c7d78455728c87f9b53aa4978374ab9592e12c22d9a760e26eb527133534ac5bbf969596b71cde8b4ef3587fa7ffa7116834348c275ad4dce68ab3397521ddc8e54380129cc81b981f9b32db20dddb0ecaa0f1ff7b06495a42b4a800a207b8e9ca38794e2fa9f40546e0e3aef7b5236d7fdadd72b1158714a5ad8d6264df1e75120088e449b9e911eddac59f1f19a795205ab7532783a93159876133b3fe3a518475a545fbe8dd2ac143f33c35d98e3ee13b63606b1e671917ac3ff9412773a3ac47b8c6627b8ba9dde6820f4f16c2ed9cb7d7086cfbb0cf2d7533eff253d14f634ab2aad3fb4289b9a0bb667a6fdd0acd5949185d53f1dd2b96ff060bb44f872a67259100669e6eaf1a7e2b11dd5fc35792db0c44a1127765934a068bf", + output: "bb618ae6b7739a4dedde1dbacf864b0892b93dea3007237d2f6f23be0718bdd29321e6b0fcb6a44dacf0f5c53d91e16165997e2302ae7ebc2dbd02c0fd8e8606a4ad13e409a4e807f331cf4174171c5fff23ca232192906b4eefdf2ffb4c65af78be01b0ba7d15b4341dd5a2edd49b17db2812358c8af0a4a9724e0169f50d1d331936bc2400012a60849876c3ead52cc9fe60173c9992f83f3e41ebd24fe3961835109612994c7620280539d483f91ef9a64c16032a35612a119589efe6357fa35b19531274576e304be75bc7e91d58015792095bb00ce4de251a52b946554366ea7ed9ce9317020ec155ae0071e022af36ad10eda5d671e5090c136e381cecdb8bc179474fabc7dab2d8a134772976cf0791b6cebe2333d34b4b8e2b6b2eab2b5dc7c6a08a583d091df64328cbcde36bc1b81095d82c741a1503c55d833d551a855e098166c5efffb8e4146e32e54abcaa85076ca6660abdfca9e82824217b5d3f23f7ff3455872bc76751480c1a8e3e725365c82fc135cd3713cc0f1ea733754142f8c37716a2a4fa8a6b898215c287565325774c2510df6b49e78cb986853ac5ca532c9a7e2bceb7c0157f60433f29fe29009343d6035d7b5892c77f821b644590615dc505604501dd218dcab789e6f0525387919cf25c7c6d62a8979e39d346decbed2657", + }, + { + length: 511, + nonce: [3]uint32{0xba68c47, 0xbc020097, 0xbf7d14a7}, + key: [8]uint32{0x3bbeedde, 0x6e8f4d6c, 0x6e27cd72, 0x140ff360, 0xc891efa0, 0x4aaa227f, 0x733cfef2, 0x2b51f1f3}, + input: "96eb94e1adbcc0646440c8824a2fc0f2c4b17d9cbddbb8ba8d9dbd6482fbf7201c74eb923153e0138b2f6f182f9c3d5656ee40bb7c26a01740b5c7d125261d4e4197614800aa152b402ba581bfbf4288e73c9ef7e7e37491212b921420eaaff880eeb458e3d0aa108b01b53492c97e328e9d10e3220b924351d583c00e76aee9325d6b89b1f162ffa30b386b37b5eaf4dfc25d22987dde4496158818c4d8f19ea300fe140be921d3f1abdaf9ab8946833a57cda5f41f995ff80e98b0f10f7afd736dd33438dfd395547f11563056078ff8f7c202aac262955f0ca5dae2365472de40f069028104ac552ea5a45ff2773335e5d3242f1e62e0e98003333dc51a3c8abbaf368f284536672e55d005b24b7aeba8e4cef23289adc12db2213aa037c797e7e753ae985568199cfe14cf1704fbca443e6036bdd05859e3583897cbefe7a0cf268b75d554b2da6e503ee04b126fbf74eaac0ebca37e84ab9c726973af780fe2bc9869fe67b7d9e4a04062ee535b2c1740d1347224e211b5cd37ee14c3325f40abee930eb6a1634986e756b3a1f86a3d7ee7184d95ea948506d8ab8b23f92ecf3eb0586f7a8b1bc227e08a0e32ca75ca4eeffc5c0a2a623547788bca66f3dc2c48671e462544d52a87d34307a7f111aeacb7da50262deab33d9f29dd6b47c3bb555be598d619cc66be8c4b74b01772725268a43d467f39bc565e5efcd0", + output: "590965d18ebdf1a89689662cfae1b8c8a73db8b26941313006b9b9bd6afa6a57149d09a27390b8883069e4fc2dfcf75035def1f8b865e24c21b1a1ed3e9f220d7b48046577b661bc92d9888a912984ad415ea2fc92c9e37da0bef5c7dab11495c612c27b5babe6eee28fd26482272fce69ca7f11bac95251735ad808365ac587830ec04105304f8e440a4da47d30e788718da4282941c9c76f18de4f954b8be750b54cb1145489edf273625a0df9a694a23fe7bfea12579b53c3b2a3de85705568cd7e603f3b8beba9a14cad9979ea283a8a291d3e1105b7f890e2a569804d9b7dd4c7e50bd0dcd11223fd7247af77f04212ece1b98c238d2fa0386a994bc502f83dcdd2e5a0d45b185155e1a395d91726d383c2c198fff1590e983c65ee041638510787c8c59c2e96f31678226a033e027bb40c416b73c3dbef31affc93a659c8ec7ffeca313fd5283a80533b2d63941c8f245d22b160c5fe57c5fa4b759c407b9acd6d9c4f80f244360b9acd11e2b43d4af757e16a6ef9d6756df39ca3a8a235e74351f50b2ebf54df633c8c400fd80b41b07117676d486377095660f2f20f62c034563b4560b473a8f4d6a740306d2a822fd8bd98012a840ba9b1709df9a0d61ecc305f7180fd764e334045d9a8ca23cb8036c05616a8b21fc488429ba4168c59dfa231f0ffa668a3be7b16583df1a55bb9c15d51660ddeca730d66f7a9", + }, + { + length: 607, + nonce: [3]uint32{0x9419df54, 0x4593f2a, 0x71c06dd6}, + key: [8]uint32{0x7b517740, 0x41e86353, 0xed629408, 0x5fe32cea, 0xb06bc5df, 0xaec9b350, 0xc00c2a6f, 0xb3aaf44f}, + input: "be3f309c6e7b89e1ec4a855cf161156d09f8a04d5630534ee19e9e071e3f4603f23f0c59a7b7f8a32c4c203ec8c129a268faba09abde7b61135c6c37fd091e2d695f0e242488098ebed30c7d321f4dcef0bdd23fa85a53569868cf2008bf4d2ee7a12a6673298c7e797321b9f4559748223b590e6fcf17aa72251586b01181cefcd32c6a1a20a0fc27143426f6572b1aab0e7301e390cb857f912d78d5153906c698ee140b36cdc72693cc019cb7add747ca3a07b2b82a2332bfa76c962b186ad94209fcf590ed0f6a73b08a771a58eb9649f2f1da4f7c385da83d50c939231f745514d14b0920deedd9c4dc6d2e547f83643d13541870875e52c610372b14b602e7a47f0b3721cfca60ec68e2eee91f40ceba2d0fdb4ebe19cb1d1ab170726c9e600030454ef355f9a40033672be520e528937f38e7a862a5ae50cd94f667cd015a72ee3f91b1a09031bf4c207e0c516b2e7a4baedf373f1ee71843e560741ed3a3094d2b513e2248caf27ce135716f6887d9f1fe5b11e02c12c989d29054ab183a3f55d9b40d78e12ff56edf936ab966c7c3130bea472b71fd69e70165a76afbf720e2c1587a77943b35acfd81b2ab6f39476623edf3663024fb84da8057ed3a361e9533caf9fc58a5e4897e4bf84f58ed063b5c353bdca3792952eec0a1404149ebeb5b17cd6350ab3e27e44e40fbcb00780d001a48d0365d534ff830553409919608881e665f83bb5cf0736d728c41cc4e985c377f89ee1186303d0d76bc634875ab3ebd87059969f24b0464ae11967bcc47f300a34e3b917b1affceea716c5ad9abf1aa3a1106e2f4d006514dc62cfd2a52426968f2f3991c9f9d8fcd", + output: "e4032c01bcece73fde73961ed216820dcb44ce20134678c98afb674bb03afec2f4aacbade7f87a32fff57ae9213eaf0509e9d9db1313b06fd1df53561f85896ba627cccd2d0e2ae4f24f5579bf02f6599f5e63412ba084cf53a5bc9a8061b5c029b755329fcd73f629fadd3bcf6cb4c572fea86466cb5159d19eaaf0f44c3471d0323bc7206bb514ed8117a61c6d98d44faff6a83716657531d965ba3efbcf067c452e0d2807db3423958d9a4421886fe132d7c47e82086db9507616b67f0051dffc1a49ecce3ca8e4d5f5af15684cd8837a471430ddd333ea0b6ee603b7d9e702692f857fab060ccf26f2a8e61dfd3b12923acca78b83a6004e4ff09113becf6bdd0bec3a449a195559dfeafd4e2a79ead5ae3c993a15ad9b1a2ce818e18edb010b7fece9aa437d85ba9841d89026d6aac1a3a6ab6dad932a26d7db6f3664b06d51584cf4d22a75c06e2840db7292798306e4d39379af85a6bc8dcaebb5246e07fadd5e336f122de0ecb99ca24a971701a1f43bd69933beef6e52d299b132e7510caf27b99739e32bd272afc36755ea80cc7ed3957d91325584b338d15b19fe554ee70bee903babe21d0cbecd49235c70a3a4f516ce16761d1cfcd70bb4b9c7c73c359f3fdd0753d6c1ac1a1463142f18266b6a9c84675f247d56563646fb2c8c3b6b81944c2ba2b76b685ba5ea40cf539bcf3850a8af3e0a69c0b38164de520a3bea82b91f67d36bbd87877b5be7f06c2d26b2dc747a26a51f51fe293197db0e91e6ac617c71ddc6edfeb7db8f067ac2012268deb7e5f00a640c1bbec5c4c71f10f921071308cadededad5c90e72d744d0bf790b043fd35729570889ebe5", + }, + { + length: 682, + nonce: [3]uint32{0x17cebe90, 0xeffe259b, 0xbdf9d4ca}, + key: [8]uint32{0x172d51e8, 0x5b80f5c6, 0xb9c9e438, 0xa56119c0, 0x62212323, 0xf5386589, 0xde7079a3, 0x669e643}, + input: "0aa4fbce7e1774f0607e7ea01fc0e6d210bb283964ae75e180a9f6ff3d2c4d50914bfc32bca6d243eb33551521d54d66f377fdc1d31974ece79b157905ff7e7a9b064f349727ce37c83c15ae13df635c3e6b4baf994d9aa0bb90b06c6cda51deefda72c97a2993448e654b746b216d2b949bff1af5238558205cfc3162f1d7a020a919db4d4eb44bcf7b269d4df57e24133d1e540694b9148444cee16e64035ef006a6079dff449949c1b342991f2a27f21c8bd74ccf4bc944284a46e9fd9f9bfd4b95f80c05553950fabbf5e5aed6babb8427832266aa4d175114de9127ff6ee848534d6dd5aa6d2dc361319863cdf32cfb1b074faed17d368964393352df01fe8d86af0e994bc9dac315f7d9efa7bef47a16676cdf17a535ae71d399c4c11a3a3ba0491e8d41f419685258a4ec7d1ae588b3ca341719c0827ce5f5a653959a8671844f2d0293c09bc7d35497ed18c160fc7b6d073a311b621a7a37f7ded1df3d73dcba1821278c9e17a191997fa4dab0802e1ee1b468e91e4272c4569a17dc0b2805b980bde798640aa328a3605abea1865083d7446e960c27f69d32882a2a2295efc9c440dc203872373411925f8839715e9441d31dd9cc14bab09a3e03b4a63e14db3039d58725796326ea6327f189beecd63955f1409467c81f4691ecfe9f0ac5234f23dfb84e3199e415ee7b4f67189e8857ff6cb3f64c2ac1b554bfbd679a6ea8491cfd69d96d08ee2744d9103e0b044212560ff707974b1a9043e1f2c3592828fde8ab5e993652c00e2b3fdb19082611b67866ece6c4a2635f87e04d2136d679f632416b03ece4d7e9406f3437163f4fe0c8cc7b87d487f6de3b3022665bcafa847c2b9199e1ba9af7deb0e29b66ad41688d03a8369416dfbee6d03526adb3ebc4b4f8531d73589499a3010b5309e9d9d2f5a9cf347983a92722dbf6c4f0bae8aba57b37d322", + output: "a31f9a532f35f20ba604a9ab9989260e5a4ed04e6ecfa1cb9e0e1d16943906acbbb4e761a2bebc86cad0ce8b3f26d98b455e4b0835eb8b43791cea29fe8fa6e5187b60198142059bbce98917aa2957ae2555bee70e6e9e21ff6197a51ac2ca2952c413efec4d9903a2f6883e88aebe7ca8316831f6a8f2cd0e486319b58dc8db862779adff98b7f35c33faa53d56acd7a81e0feffc286b728f3a11afab7cace4c30b1a45780276b1f0ab89242410d07cb1191c7b9da5d09db7c9a729d91ac3ed82f4350f2871a12d125ba672861d1b0af7219c360a0e023a8b7c23fb9d72631c72e032c097118d90e5db0576586d8224165a8376fe8d04de93516848e7c2653cb4f7d24a971ccf4f16c527ea5b4153fad5fd5bf473b15806671854507bf1a6d9e5fe4a6f6ec977197d21d69a041dd955e199031f895adefd850c8b0ae327ba0c18ca1783560e1ff0feb2f659137e34a91e9e9ff04fe3375b7db6e4326986e6265e5fef00297f6ae627c7563846e531762748fe8d0b6baff17acf1e6c5cfefa35a95ef634ff96f83f16342a6c62311fc653d314f8a6de109356ab7801316e69a48834cb6325816b1f66d5c67d6e9c9cbc8e1a0521fd6e4bf77a7d2609f99c9579e143f530677b99d198a97620d087f058edf35eb7271701ecebb8bfde5671641ed21aeee9e7db06b932e0def91be93cf2955159e9666c770cdffa03886eb6e98dfca8f91ff5cef1927c0f82b9226d65c68d011416cbef802c264e34244ead7a6ebbe28a510a37e1276f4f3cf27a3944a08aaa23bd321092761627dae20dc269b6150545c75e995cfee0a9bcedb1ad8b364beb8839fd5c9f7984fa0a08a1a354aebe18f62acf6d6664978fcfda2ce6fc16eaa2cda5b835339001b3b98d3a407a3e18e0ec2da6ee3d1448c1ece2ed67c3f51f01e76ed59f0e61102b103a3c65aea94275e8d1f0d331538efe", + }, + { + length: 768, + nonce: [3]uint32{0xb1c9bd09, 0xdbe6497d, 0x16c73b95}, + key: [8]uint32{0xbf9d9e5, 0x2eede668, 0x631dca95, 0x4233e36d, 0xd83fe644, 0x99b11f89, 0xef055717, 0x1ae9695f}, + input: "e097b1e8dea40f63714e63ab3ad9bdd518ac3e188926d1086a9850a5580affb592f6e421abc617c103479ba39a3924eea1c0bbbb051614c4b5003bbd5fcbb8093864fc1c130748194d6b560e203b889b98b574a98ec3e0e07cb2d9f271ba7794e5419123b4f2ebc7e0d65cd404104868905ff2c38d30c967fe9d77ebdd4b8fa836c3b0ad15e3e70e9a28236d5593e761e694b047f63bc62c7b0d493c3e2528c8af78f56725172ac9416ec2bdc54de92b92a63f9ccb61e686f9249c7cc337d99b2160400bb5535eb8f8eb1e3cafcbceaa821c1088edbacb3b01b5bed977e702de747ad00268ffe72e3d877dd75816db65b5459607cd1b963fe43bf2405ec223ddc0de514d59cde74f7522dc72285caa3eeb7eae527a7723b33d21ce91c91c8d26bf36eeb1dcdfc1e9e475c1565ed9c7e64ef601874a4f277280a5ceec26717e9385aee8b159379e3feed7952b87240c942970d63351259aa7a286ddb4a2620fa67565c92f592902e49422f1eecea2f44d1c0bbbf54a9e5612b86a9549aa3e6639a924c7bbe2d3c1b5669da73c0e2c6f6f6084f54a912ad2635d0141c2f5ac925414dce0da09ab8f86eae2a7b7e48741253189e5fd554d5c04d9807ac6ffd8a4f8229a3e8ab75ca5c778bd7ec5a5c02085faba9792cbc47f9e9311f3444e6544359769e1b3eb4d42ac8923ec94536e1a44497766b5da523f5763749dbc2738dfa8e13c191dfeac56c7614a96bd3ae23e4e6e5ac00be851ac9831108989b491eaade62113c531385ef3e964ce817c8ed0857adca946467682c2f4387fab2f31ce71b58370853171720268459588d5d216faca58d0bebbd7cd83a78445d9b49e83ec2cdb59b5d760880bf60532178d60372752b47d52562b316c7de5c74af9cd588643002d66bc6260595a540d2f82cf2c07fa64e0cdd1f79877b6a25b0608c735a7d35ca10852da441fcfb31061fd7e482a0989866f9eea8b0b39c3d519715c1c2766c3ad99f041143cdb36557ed647403458155dccbb80c3a365f0a85b1135695648ab67ac76b3d219c7b77e49d735c72ac947b1d7eeb279beb9d2602aba7b36ca", + output: "7b6e07e6415660affba56047b988f4548b308e7a642c76791f5c3742cc4cb744cde48fc30e50d458084e06c6dd29a52cb4c306a69a493a17c0838d14b107d07b81c983a2dbad09b80f087ba48465a8beaae5b16e8093e17cfb9e84ea3bdb9af00889268a5c01ddf25af434de56f65882322432aa275fac8519e317ef4d89478f29182143f97350983050f5d37c4b518611da6fa2aed7bb73e614231a194fe17c9073e377fc6ea0aa491e15ca54808e0536c8c3f1bf657283f807ebfc89b55049ac8fb86f89f17974fcf0afc1a2c690c0442842d0f4af9ee29dd960e499d1077bfdad4c0c9189a6e83799bb585acdb853c1e99da7ce9c7eeb9bf431f8d364d0ea80b0a95a7807f196c6ee69fe90e6d1f5d23e5cb256e37e65826d7a111f2272884d6319f968580b3164b2697ea6556816cea3ca316651fe2fd68dfa905d080c28622606f7d24da216289fa2c54c6f42dc244ecb047512ace62f0801f2dfad8f0218f45e2b3bbac97c2176c842398b16dfa1fdfc9a68b7b5a1e785d2a0cc592bc491f5a69c81127b758ee02c66b81674d3135c5882d1dc89dadcffa06f4b0644df5c7fd65c72611d79be7ad637edd6fc38b39946aa2a2c6d08ca9d3ff9a8ffe2e7989546489539b1a623fa937c468e59e0978602526b4367de277526895aa222fbaeae2084f418c5745d8ee844da0baa47f592970c14cf710f49539c12104a62baddb3382f5773dd18c83ecb238ae2e749a51584a38e394ebadd175bf5c3cec787907abb1d94af70ae63d3b7d8d5ff254da90b78ec8fe2ea95dfbc6e3e69ecad856c9e54906df8fe39859f2014b74dc3ca0ee2a957001939d37a6c0b489bd3f1658b835a57b24aa282c23e875c9e67e6eb8b32fe44e7d7d8e285d85da0ce1b53990f9fdb5e2e74728e433ed2c1044df9e89cb9bb316c39fc6fc8bcc74a382093926a288170e857d6b7f47858a4c2d05c74263dc9e8199332d0179687f4a4cdfc80ee6737300cefba75905b22d21e897f887b67aa3051877fff11d98bf96ca5091bb225bddd5eae697f3dfb0efcdb788ebf6694b5b39dbb0d4bf9427382a3a58f0b", + }, + { + length: 828, + nonce: [3]uint32{0xc7e503e, 0xf8110ddf, 0x83316c8c}, + key: [8]uint32{0xfa2d1cd, 0x4fe7f905, 0x2b9e4c1b, 0x115bc881, 0x2922bcc5, 0x3f60aa25, 0x13c26d31, 0x2096af63}, + input: "0a1064714f20d9e47fe53250ecfec759f4137e60afaf65755f4709a483504c3855833b6dcaf7aa0180fd735fa9a73d46697f6c45004adf12452ea4c04a720fd7c20b9783b74b8b3ea0c8b1563d5a85f44af8afd7d91ca6298ca22642a684f66e365edd6f6bdb2dd32dfa13c62dc497fb341b86f65d40655931171416e23e3b2623c0b4a67d448877b6e3d4e0fe284034a10162b2b5e21639047036874f4bcde22b145b5f18aa8ff32dec81e6a5ac68b3c30c24bd8fd3b8e098a1cf202e2ab2a3bb66a9393222b9f7384653cda7707f00bc3c81e9591fd040a07d3629410c2db78781a4c9db3df5f9d648162f1b087974f56a89db07aa21ba827e3864a1618945b2fba06853a13c35da2909f5013feb313bae09870b8eab904024adab0d6ac46c1a1499791b47413139dee59db676949b9e9ab8d3d6abaa954ec2a9fc83953c91b483c3b6bd6700b96484850734e72e3710a1b379c0d0698aeaf68f13a0d317bfd689471e3299288e7a383a58522f0daaff210cc4917fa05f0b8ceefc2afc46148a05a100d30787accfb4da094e61ea6b58f132692aedcabae928e53c2594b01507b8fc2d0a85a1d111d1f4de0b95258281ae01873a72606753b6f878ecd8c4f613fb3477710d260f0bca0d4c06f675ab7113eded395f88755a98a0ad22b4a002cfe9447c4e39eda13738f4eccb9c13367ebc2878257c4647d31b67e5e32b6a77f23e9593658d19c0a40e8a7228767afba1cf23072b013b2d76ee66e42b57bec2797ce3619c695a661004c8129cb5c5d6a2836be22483f3b7e40bf8ac5535bf6cd065c4821a87829948c88163cfe3c0f60cea4e7ff59df4cdbf80064b2d664b39487413039999b5e86f1d467b12682d0cd355e9f7cd980e87d584ddbda89f68632d3b8fd6bc3b80205d7feb97a46842b093f74aa14bb21accda7474247b5e39ac76ef75e9b5b52b6a829a7e2297ab88fb0eb690d54ab1af2d7437149a6202035ce15f1e6c6267458d62677c263d83d3f8119af191b7d766582620e0f08b411c996c25ba6a32c2d73f592e789ed662e94103329bfa5e6573f1116ec04438997f3e4ad91b4123b570743455020d914bde2d8417fb24671e6db261732fb89dda1a36614b095529e4f97374c9bc0e55aa577bfffa663c816ca9fae3472e0a", + output: "b00a7caf5359c5bcebe590e6bab9aa03370050c55cbd45a257f4869937e922a15f2d38121b1493d6b5dd4a8a47d7b4e5cb049d396ad84ed421df774b0408b6939f18ebf5cf83f48c540affcc2a885967bf4bd222c42904b8a73c4185bde3f97e874fad25b46714235e60c9ff53ed2975c9c85ebad0752249e4b627ffa41555eb9074f63a5f7d61d207d2ce11b2a9fa23a13a0832eccb91efa2afd8d9acfee94ac78a733fa156bfea5006da1d0127c32aadbb75c015b68c627903e1c85bf3a1a9f99c6cfbdbb5c871f7f9661b78cf5e16d819f53e9930e201d4f58e69bcdce77ec5b9b1d2cf206a71f744342273c26b9abc71303c20df3d51f52222893d803fc8e0e0afcd99ee1c7f95b48680403566f7f9e296d7ccc0ec348b6ad515af58d11fd82c628ea29ee6a5d67aaeabd8823addc01a078b04313af73105d4ce4abef8e6ee8ce649640a19678292d4f1017d121549fd2c19ba6cdc0b613e512bc9551d759c6d38aea7e35c0847a142e273a16bb1495e652f9668b97801ba3f6d9931c0a1efaa4452e15732dca1ca9cb45ed289e0fd08d1cee1cdcc9dfba8d0b2562b0b1a180f4ee69d63573222c8d4789bf0d63d2a201a70c7b27c84e620e33e8a863cf49b784269a51ead3d4ad26f044d5859988d5485a11533ea805f5a8f6313caa6b421071a34f57170fdd8e4663e9a4cdcdcc1ddaa9f6e651fb365cf827667b018ae7d028c7f96295b2b4f9eeb4b361b48af86463a79f50b107ab0935e3cec3f4f203cea801ff95fb870d2c2f0e315dc8a6a547dd3c390a1f5403917315164bd2d40362489b389a54e8dc0ddb83e6a43a26c65923e6f76ee0ee0e3a33b0a9066620a01f0319e20b9f1beb3910ad962a3000e6aacb0ae57f3f6c5e0315be5de93edcf0e45e0e47332f9daf7f33e6e8bf1929910b78b8f88ca12bf5519a3217b7554c8c8350cc314561d580bf67a3878e3979430d070121a5e070a3458742e8549bda972f603222e2b30eb8a49a955805307e6e02f8c60a08188f69340e116422458d4a8841f46a78c833b1a822e3f6c9c97422c918f17c36175ca4b3d1c081ee4b175b4b07bf101c3836eb5b9e3cbd08a89b4a1c50edcb41ea8ea6ceb1532f5b842715d50dc21e2499e08c373d3dedb96bb477c8802ab7aa957e0b5810f38", + }, + { + length: 859, + nonce: [3]uint32{0xeb02dac9, 0xa7cba06c, 0xc24764c}, + key: [8]uint32{0xe9414a57, 0xd5e29546, 0x1a5e2f4c, 0x806e4c46, 0x48098d1f, 0x4351ca1a, 0x53ed97c, 0xa6a495ca}, + input: "00fa3b13b5cfa9b5d65a41cc2d3c420518802c22c4582873f1ad52a22032d2cef7c975078b199787e852fb1f914529f60d1cc854e5d6d547216dce043e0fc94866bb2193343c3a07fde60e668266d1cee3067c6f2ce0f9f63456ad08094b6c7f515f7ca90caa96494e2a6835ba1f3f166012ad1ff6af6b5f8455d5c26e72402966af9066ca70ad027eed23b0eb02c751195064a62283975efeb29bc5993f83360d012a2f5275ac758a9e8fe458fc7cc0673e6b9e338678f0faff60a67fff3784c3054dcbd95d1b00ed4c6156b3831cc42a2ccdeee55541f228b88e6c318e2d797c6fc035ae12868c4a4e3843b5b25a530b1477dec3f5ac27644476b5766e0ee132d833f9a63200eb0980bf72c3666150e567e01e3e1f469cf36beea65946fce714a3f354983e54ca4315b57ea35c5f48bd5eada05f49db1004cbb39888ebab3afad62f6509abad77ca8c4ff28731c7ae545e6876c8f4a80b6cc26928ee05001a9764694b52edd605e182d5a3a5fd192bff58aba90f57e4debe612d02cf6f08af33a78ebf8823bb3eb46d4da25b7dfa15ad436c380633d3db3d0dc4dfec6c2324d105e7090e65342b554854e777b40b5dab8125a58e8b212364ff88459a8466ff5ae661034abc8286a78ad5aa582e2dabbcd7a0b0cedcb9fd5f0bb8c3bef9117f2ca6520a72b94e528c1a4a464398e654995d5f4c77cbabf2b204b96a058cf1b38284b34e41ac37b05a003ed51be9602050f21c6b9326714bc425c1e22833da95a6e77571691d4dcab4ef9056c4c7f85d5b445b902eb375b5164c6bdf629ccfd4127a6c024bb6c4da0b6b08350432e58f8229e04e2e76f704be17d36e0c04fcc7a98f721d4572aa7f66ae8e9664300a189bc3862da47b60c8b33424f6d577cc10f4755f36c2a6decc30ba81bf48f96616ccfcfb74965d6bdcab82728bb224c560d1cfd7a175413ad1c14c734746be3b062b4e7514e9075c688103515e32e3335dbd272a315024d56f4ecd354264da9bc712080657b2b51b06dc7c4c441d9858935a4c3e6b207bde38ea83bba4c6854b2bcf914d758e0a174c0528e0e385c7cff355c38db1c22440369141e91266824c59f1ed23e7d4b99d31b0baa7bed4526e24259dbef5c9ae275e97267b756645f804c274d65ac7ab0f7683435bc2e4f24075cd1b790aa2b53fbf044e8f2092bdf0dbe88a582ff8f8de291e8220", + output: "bea32587095caac661c3ac49e65654b282192b2addf5b9a403aea6c8bd0096291a0a66ca4062acf1da91fb5749952096ec63ab652ecf94c29807f0aaac939b6896edcd6f0cd8dd8d208b906ef4d7a8766831fecd6ce98f4ea0c34fa9a5114dbeb23c2cd6d3aa962e39b18cb343c24e65d49fad0a0fb50736f8d2b24b011108932484399f4c4510ac9a5e6bc78ff0b450e67f87b49f253b99d95d6294e15a9934fc8b89a5913c08f75d3516766fb0f60f82e2b2647b4619991c78adbcf548c07c0dda30c629349d84f298313c3e629e03760b1cf860264205a950d6fd86732a6513827f72c0dff5aff96f7203464f60849c1065beb70f282cca1334f6f6c767dfff94f063361f592e85597de5d313eaed17bd533db24818d9ba9aea2afa797721fbd19eea7b8d46bbc4b9dc0164636d2e754f5e9e8c04e2a381096331731c645ea1f613a37bfa9a6fb2c6307e9bacacbeab7f5672163ff9742a8115049bce0269d7d5f6f35787be031dbee1535b0516ec0b46d12f5833cde5f2cc569edcdd20993e9776aacf48ace7bfadf79065f2803fba6b2b27aa622abb7ae023ff2b27b727f509f313f92026392485a5ed4fd53b2e22b2d2dc1538ce158d34921214638be30ae054a0f5f1d4f9c590a2d215ac2a5b23ed33871ab26c8bb6db7fe9d6f51e527c9547248a4e9734c64658b22893f4f6867a35f18e2bbfd7d62142025955cb51af8e40b6fcb91c7e959cea2c92022c87c29dae107a306f41b00e73c7bceef8cb070e8f9e830caeee463170e919cba6eee63092a5a7ee33b74db09cdd022fdafbcd5d524253a29a103ba6f4d668d31d18f867557871c0e0258221c3050d57c18bdae4cc4ff8da0daddb5c08619be127ee76a317b59a9d8e67808603a1bfce6b4e0d070082b283bf9c0e6ef8256208e482f3e2d1a40d30807f60a868e2279dfbc3586d44ee25fdca3505cd39fd469c2cd03bc2f921d22a8346750f346c919e7247301c1c8a4a3ddb8eabc6e80d85cd2459afe1cbb4851ea2c86b8075e0fef3177cb074894410ecf681242fac62b5fa4ed3a10ddaa595427851d376cf69e350207b667f7aa26d003f1ec739a8792532ebd93f3cafb1fea40d227bcadda2fb6da794cea3371240f257f80b1b8a857ea453b46938397c1f4b303a46257750003a60666a11d03bf2afb5c71e059933d617288891733b63784bd9c662234f", + }, + { + length: 985, + nonce: [3]uint32{0x3c2b47a4, 0xf614c813, 0xa26f7014}, + key: [8]uint32{0x39bd3d18, 0xc9aacd67, 0xcb5485b5, 0x20536a22, 0xbb22ac87, 0x1c9da580, 0x7d996b2e, 0x456fe461}, + input: "01847d8a97d56e55e12f89adb13c8c0f9dea5555e8dc61171fbb8e181f6cf846a4dd68b2c75335c0896fa215bf7f9eb7e398e4520aaaf33461ecfb61051f43d43569fb75fabd79d319bf39469f951e4da7932a74624c46d8d26a9499c701c00d3dea57a6f65b4c0f33b568d13989340294d17cd005b26d89cf6fa1c88e7b6ef4d074291fa8c117ae05d7c785459ef4561c45af63a811e9aa1c31b69a5bdac2356d955a0f579791247a757a691b3de447a53619878397cd82a74053f06da3574045bc856500ec01fd2afbc64d8dd283ac876a50e9396f78c424ab157f481316fd9c90cd899f5aca46dad32c68f1d64ea7f1c4bdb994ad847072609bd89adc2fa8382a5d573b680533640b8321b6adf27926274660b2cbaf04fbc9a4fb17ce8957c38c7bab1aafd5bf7263171e47d2e1ae5cf0494815642209d303dba561754479c24ea01a573c9083b68acc49907b1748924d3c6a82feb9417ca932578c123f9db35521c0d992565f7396f0c23e436289c1720e4e7c6e285c04a8159f93e06801334e523b18fe188355cc6a155febe64ba053e6b5d1cc87787fd5ae68fa86d8c51868b9f6a9664cf0d56aa6cb8463362bb671e6b8423bcbefe2a1a0acba3f135496736b5cec5e329494af46aba322bf5d1cc108c98298459558773a316e09b0bb960a26f4b0bfbaa493b5f98a0e522b6203c471b10e662abe9b9e60de2a1517843933add02017fadd62608383ad53796159f3d21b2c8ed7295802ca79ea65d550114ca2bcc7f7c3b4c6709fffc3c2de00da06e83d8f0cf04b8c8edd21c0fc11a0b2aa7f6adad255fef25e5c0a9d59546e97446e1fbf6a51a8ea6cad54cabfdd19cd10d7d33ff0549b710557e3931821dd8809ab0a9d3aaa761a01ae0f2e378906672924d6a1b12fb1cca7bed41f31974b9917a05de60c32796f502e7035a2c01cb49bc8e1734b9fa138b81b4dfe19d37f5942dd1b42f03e1e5a6a046ecd457174150e17dd148e4bfea44b72da35ef42a7251244700e59e702033677d42611168fd246e1b18b9a464b6c20fc7fcf6360cd00466ece059a69d7d54a4f5565d08799f85dd3c849a08ba43415077c1c0e5dbdba52bb3167ee99a11db551f0260493be1dde58d2072e8c02251f4f574b6e115cbb6136dc2c3fbce75fdcefe812d9c07a91a89088985a52cb1fb9f6cef80fa30364706414175e42c75e8e37f6e7cd028c99f59caa88c49db5b46e8d6301bc39034013718a9eeef5506415016fb21d70e46a03b4c5ba72f91dd9321ff5e210e5e5f7b0723a3bc4bb02b5a74c1f4a63aa5a993a31f79a768fe8033c9abfeb4deb536af1054be02d8d1c4a6a0fa75f3eb787d57a03b7ae994fb1b54b2c43b230ce32e6245d944b3cea4fa6", + output: "785dbea5d1e50af4743ed5fd2209e441fc7c50bc7f6fd9cc7f24654c619e2606178dcbbd81a1f94c1b3176837024098bd31326145be326b32fd9277a55a6fb38780c8dc8b471a3184379d90da4aa87d80b889b1f4d8d0755c1704a526b99ac829b8ad157ca54b2b05ff8b2917e27b0c147ab54add9a89fdcad7b93ba1fe2d5be9de88b68a5324f1b42943e45ee31c4ef783ec9e2337b3f2834b10cf452b313fafdf0c03719140f64060da0a565e185cb8e544e1c185ca230ff2321739a285abe8be4be0ce76678a7b0902a77a645194de49fef8ff64cc464ea25e1f1d72c775e450f08ddd7680d27a4142879787b198583d93b84cd87fd5b4063d92d13d9c9cb580c01fac0174686a18f64e6fa0b3589624cfae04aad74950559bdf92b2b199c60cb04013aa0ef56d1f9ec5b7e968f6a83756ecc9cee7dd8b433f64649f948df5474a64549e71e46fd8bb16568d21f5fb67f5ed555f2b8aec4709383e8cbc45b9fe47c0434178ad4c6d0d42606d6eef0e21d0370898d1d5d646830a88d5f024094fe9c7a2003ca13d20ab7cd748dc11a22f578ddab416f3500eff3d89fc177b46436108e2e2c7973910cb8454a01c9e9b98f966848325444b2ac205b1ed6919fa76aaf63717574761b7f62b10649357df49f85a845a30b6acd57fa202fe58673930ec59399f537e9682b1f5f6f409988789a8e0c1f803478dded14b40d3b6eb3109758efeb6a7fe21f41c4dcc8027258da27ad74010839dbfdf8fe55050511f85c321e653f76e55f22248f46da529a380c6b1a16a19ce73af9715545c2cae098dc42dd61248dbcf7b295f4dc6b8930b41baeef677156c534869be65e723e1aa0336e8be8a3b138f840c9cd63bab6d9d61f239a47d8cf56258544e6ef65edca27069f7a57f087a7cc021fa1294b75c0c0f1093c025e426e4f041ed5187f358402676d5da5fb6ceba76a178f65c8c3046f258531c165b8808bdd221c59ff56e3e06247576e144aac01ea96a07f1be15d7a2b0b3b6c259a9133f8a50b56154ecf9f61022f470027247e6e70e6eaf7ece5e324ec8f95667ffed10337652b119e7cb8d197e306e81ea251340b9fb2c33aa230c0a16e1ca783f9344b3acbf413acd96616e6d477dba90e39326089934bc5ca6620855cdc442e25bf8b8debf335e16e7e25cceb68659cc81b13a507fbd9f30b347126beeb57016bd348fe3df592d4778011664a218227e70d7360d139480500b7f6f84153e61ca4dea105875e19ce3d11a3dfd0ad0074035ff6a9fac0ece91afd8be74c168da20c8baafcc14632eb0e774db758a3d90709cddf0266c27963788c35a842beea8ba2d916234431efde4bb32fd7e1cef51dcf580f4697206bbc3f991f4046360aea6e88ec", + }, +} diff --git a/vendor/golang.org/x/crypto/internal/chacha20/xor.go b/vendor/golang.org/x/crypto/internal/chacha20/xor.go new file mode 100644 index 00000000..9c5ba0b3 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/chacha20/xor.go @@ -0,0 +1,43 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found src the LICENSE file. + +package chacha20 + +import ( + "runtime" +) + +// Platforms that have fast unaligned 32-bit little endian accesses. +const unaligned = runtime.GOARCH == "386" || + runtime.GOARCH == "amd64" || + runtime.GOARCH == "arm64" || + runtime.GOARCH == "ppc64le" || + runtime.GOARCH == "s390x" + +// xor reads a little endian uint32 from src, XORs it with u and +// places the result in little endian byte order in dst. +func xor(dst, src []byte, u uint32) { + _, _ = src[3], dst[3] // eliminate bounds checks + if unaligned { + // The compiler should optimize this code into + // 32-bit unaligned little endian loads and stores. + // TODO: delete once the compiler does a reliably + // good job with the generic code below. + // See issue #25111 for more details. + v := uint32(src[0]) + v |= uint32(src[1]) << 8 + v |= uint32(src[2]) << 16 + v |= uint32(src[3]) << 24 + v ^= u + dst[0] = byte(v) + dst[1] = byte(v >> 8) + dst[2] = byte(v >> 16) + dst[3] = byte(v >> 24) + } else { + dst[0] = src[0] ^ byte(u) + dst[1] = src[1] ^ byte(u>>8) + dst[2] = src[2] ^ byte(u>>16) + dst[3] = src[3] ^ byte(u>>24) + } +} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go new file mode 100644 index 00000000..f38797bf --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing.go @@ -0,0 +1,32 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +package subtle // import "golang.org/x/crypto/internal/subtle" + +import "unsafe" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go new file mode 100644 index 00000000..0cc4a8a6 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing_appengine.go @@ -0,0 +1,35 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +// Package subtle implements functions that are often useful in cryptographic +// code but require careful thought to use correctly. +package subtle // import "golang.org/x/crypto/internal/subtle" + +// This is the Google App Engine standard variant based on reflect +// because the unsafe package and cgo are disallowed. + +import "reflect" + +// AnyOverlap reports whether x and y share memory at any (not necessarily +// corresponding) index. The memory beyond the slice length is ignored. +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() && + reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer() +} + +// InexactOverlap reports whether x and y share memory at any non-corresponding +// index. The memory beyond the slice length is ignored. Note that x and y can +// have different lengths and still not have any inexact overlap. +// +// InexactOverlap can be used to implement the requirements of the crypto/cipher +// AEAD, Block, BlockMode and Stream interfaces. +func InexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return AnyOverlap(x, y) +} diff --git a/vendor/golang.org/x/crypto/internal/subtle/aliasing_test.go b/vendor/golang.org/x/crypto/internal/subtle/aliasing_test.go new file mode 100644 index 00000000..a5b62ff7 --- /dev/null +++ b/vendor/golang.org/x/crypto/internal/subtle/aliasing_test.go @@ -0,0 +1,50 @@ +// 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 subtle_test + +import ( + "testing" + + "golang.org/x/crypto/internal/subtle" +) + +var a, b [100]byte + +var aliasingTests = []struct { + x, y []byte + anyOverlap, inexactOverlap bool +}{ + {a[:], b[:], false, false}, + {a[:], b[:0], false, false}, + {a[:], b[:50], false, false}, + {a[40:50], a[50:60], false, false}, + {a[40:50], a[60:70], false, false}, + {a[:51], a[50:], true, true}, + {a[:], a[:], true, false}, + {a[:50], a[:60], true, false}, + {a[:], nil, false, false}, + {nil, nil, false, false}, + {a[:], a[:0], false, false}, + {a[:10], a[:10:20], true, false}, + {a[:10], a[5:10:20], true, true}, +} + +func testAliasing(t *testing.T, i int, x, y []byte, anyOverlap, inexactOverlap bool) { + any := subtle.AnyOverlap(x, y) + if any != anyOverlap { + t.Errorf("%d: wrong AnyOverlap result, expected %v, got %v", i, anyOverlap, any) + } + inexact := subtle.InexactOverlap(x, y) + if inexact != inexactOverlap { + t.Errorf("%d: wrong InexactOverlap result, expected %v, got %v", i, inexactOverlap, any) + } +} + +func TestAliasing(t *testing.T) { + for i, tt := range aliasingTests { + testAliasing(t, i, tt.x, tt.y, tt.anyOverlap, tt.inexactOverlap) + testAliasing(t, i, tt.y, tt.x, tt.anyOverlap, tt.inexactOverlap) + } +} diff --git a/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go index 53ee83cf..a98d1bd4 100644 --- a/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go +++ b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go @@ -35,6 +35,7 @@ This package is interoperable with NaCl: https://nacl.cr.yp.to/secretbox.html. package secretbox // import "golang.org/x/crypto/nacl/secretbox" import ( + "golang.org/x/crypto/internal/subtle" "golang.org/x/crypto/poly1305" "golang.org/x/crypto/salsa20/salsa" ) @@ -87,6 +88,9 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte { copy(poly1305Key[:], firstBlock[:]) ret, out := sliceForAppend(out, len(message)+poly1305.TagSize) + if subtle.AnyOverlap(out, message) { + panic("nacl: invalid buffer overlap") + } // We XOR up to 32 bytes of message with the keystream generated from // the first block. @@ -118,7 +122,7 @@ func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte { // Open authenticates and decrypts a box produced by Seal and appends the // message to out, which must not overlap box. The output will be Overhead // bytes smaller than box. -func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) { +func Open(out, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) { if len(box) < Overhead { return nil, false } @@ -143,6 +147,9 @@ func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) } ret, out := sliceForAppend(out, len(box)-Overhead) + if subtle.AnyOverlap(out, box) { + panic("nacl: invalid buffer overlap") + } // We XOR up to 32 bytes of box with the keystream generated from // the first block. diff --git a/vendor/golang.org/x/crypto/nacl/sign/sign.go b/vendor/golang.org/x/crypto/nacl/sign/sign.go new file mode 100644 index 00000000..d0762701 --- /dev/null +++ b/vendor/golang.org/x/crypto/nacl/sign/sign.go @@ -0,0 +1,90 @@ +// 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 sign signs small messages using public-key cryptography. +// +// Sign uses Ed25519 to sign messages. The length of messages is not hidden. +// Messages should be small because: +// 1. The whole message needs to be held in memory to be processed. +// 2. Using large messages pressures implementations on small machines to process +// plaintext without verifying the signature. This is very dangerous, and this API +// discourages it, but a protocol that uses excessive message sizes might present +// some implementations with no other choice. +// 3. Performance may be improved by working with messages that fit into data caches. +// Thus large amounts of data should be chunked so that each message is small. +// +// This package is not interoperable with the current release of NaCl +// (https://nacl.cr.yp.to/sign.html), which does not support Ed25519 yet. However, +// it is compatible with the NaCl fork libsodium (https://www.libsodium.org), as well +// as TweetNaCl (https://tweetnacl.cr.yp.to/). +package sign + +import ( + "io" + + "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/internal/subtle" +) + +// Overhead is the number of bytes of overhead when signing a message. +const Overhead = 64 + +// GenerateKey generates a new public/private key pair suitable for use with +// Sign and Open. +func GenerateKey(rand io.Reader) (publicKey *[32]byte, privateKey *[64]byte, err error) { + pub, priv, err := ed25519.GenerateKey(rand) + if err != nil { + return nil, nil, err + } + publicKey, privateKey = new([32]byte), new([64]byte) + copy((*publicKey)[:], pub) + copy((*privateKey)[:], priv) + return publicKey, privateKey, nil +} + +// Sign appends a signed copy of message to out, which will be Overhead bytes +// longer than the original and must not overlap it. +func Sign(out, message []byte, privateKey *[64]byte) []byte { + sig := ed25519.Sign(ed25519.PrivateKey((*privateKey)[:]), message) + ret, out := sliceForAppend(out, Overhead+len(message)) + if subtle.AnyOverlap(out, message) { + panic("nacl: invalid buffer overlap") + } + copy(out, sig) + copy(out[Overhead:], message) + return ret +} + +// Open verifies a signed message produced by Sign and appends the message to +// out, which must not overlap the signed message. The output will be Overhead +// bytes smaller than the signed message. +func Open(out, signedMessage []byte, publicKey *[32]byte) ([]byte, bool) { + if len(signedMessage) < Overhead { + return nil, false + } + if !ed25519.Verify(ed25519.PublicKey((*publicKey)[:]), signedMessage[Overhead:], signedMessage[:Overhead]) { + return nil, false + } + ret, out := sliceForAppend(out, len(signedMessage)-Overhead) + if subtle.AnyOverlap(out, signedMessage) { + panic("nacl: invalid buffer overlap") + } + copy(out, signedMessage[Overhead:]) + return ret, true +} + +// sliceForAppend takes a slice and a requested number of bytes. It returns a +// slice with the contents of the given slice followed by that many bytes and a +// second slice that aliases into it and contains only the extra bytes. If the +// original slice has sufficient capacity then no allocation is performed. +func sliceForAppend(in []byte, n int) (head, tail []byte) { + if total := len(in) + n; cap(in) >= total { + head = in[:total] + } else { + head = make([]byte, total) + copy(head, in) + } + tail = head[len(in):] + return +} diff --git a/vendor/golang.org/x/crypto/nacl/sign/sign_test.go b/vendor/golang.org/x/crypto/nacl/sign/sign_test.go new file mode 100644 index 00000000..0a6439a6 --- /dev/null +++ b/vendor/golang.org/x/crypto/nacl/sign/sign_test.go @@ -0,0 +1,74 @@ +// 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 sign + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "testing" +) + +var testSignedMessage, _ = hex.DecodeString("26a0a47f733d02ddb74589b6cbd6f64a7dab1947db79395a1a9e00e4c902c0f185b119897b89b248d16bab4ea781b5a3798d25c2984aec833dddab57e0891e0d68656c6c6f20776f726c64") +var testMessage = testSignedMessage[Overhead:] +var testPublicKey [32]byte +var testPrivateKey = [64]byte{ + 0x98, 0x3c, 0x6a, 0xa6, 0x21, 0xcc, 0xbb, 0xb2, 0xa7, 0xe8, 0x97, 0x94, 0xde, 0x5f, 0xf8, 0x11, + 0x8a, 0xf3, 0x33, 0x1a, 0x03, 0x5c, 0x43, 0x99, 0x03, 0x13, 0x2d, 0xd7, 0xb4, 0xc4, 0x8b, 0xb0, + 0xf6, 0x33, 0x20, 0xa3, 0x34, 0x8b, 0x7b, 0xe2, 0xfe, 0xb4, 0xe7, 0x3a, 0x54, 0x08, 0x2d, 0xd7, + 0x0c, 0xb7, 0xc0, 0xe3, 0xbf, 0x62, 0x6c, 0x55, 0xf0, 0x33, 0x28, 0x52, 0xf8, 0x48, 0x7d, 0xfd, +} + +func init() { + copy(testPublicKey[:], testPrivateKey[32:]) +} + +func TestSign(t *testing.T) { + signedMessage := Sign(nil, testMessage, &testPrivateKey) + if !bytes.Equal(signedMessage, testSignedMessage) { + t.Fatalf("signed message did not match, got\n%x\n, expected\n%x", signedMessage, testSignedMessage) + } +} + +func TestOpen(t *testing.T) { + message, ok := Open(nil, testSignedMessage, &testPublicKey) + if !ok { + t.Fatalf("valid signed message not successfully verified") + } + if !bytes.Equal(message, testMessage) { + t.Fatalf("message did not match, got\n%x\n, expected\n%x", message, testMessage) + } + message, ok = Open(nil, testSignedMessage[1:], &testPublicKey) + if ok { + t.Fatalf("invalid signed message successfully verified") + } + + badMessage := make([]byte, len(testSignedMessage)) + copy(badMessage, testSignedMessage) + badMessage[5] ^= 1 + if _, ok := Open(nil, badMessage, &testPublicKey); ok { + t.Fatalf("Open succeeded with a corrupt message") + } + + var badPublicKey [32]byte + copy(badPublicKey[:], testPublicKey[:]) + badPublicKey[5] ^= 1 + if _, ok := Open(nil, testSignedMessage, &badPublicKey); ok { + t.Fatalf("Open succeeded with a corrupt public key") + } +} + +func TestGenerateSignOpen(t *testing.T) { + publicKey, privateKey, _ := GenerateKey(rand.Reader) + signedMessage := Sign(nil, testMessage, privateKey) + message, ok := Open(nil, signedMessage, publicKey) + if !ok { + t.Fatalf("failed to verify signed message") + } + + if !bytes.Equal(message, testMessage) { + t.Fatalf("verified message does not match signed messge, got\n%x\n, expected\n%x", message, testMessage) + } +} diff --git a/vendor/golang.org/x/crypto/ocsp/ocsp.go b/vendor/golang.org/x/crypto/ocsp/ocsp.go index 589dfd35..f079d9ea 100644 --- a/vendor/golang.org/x/crypto/ocsp/ocsp.go +++ b/vendor/golang.org/x/crypto/ocsp/ocsp.go @@ -63,7 +63,7 @@ func (r ResponseStatus) String() string { } // ResponseError is an error that may be returned by ParseResponse to indicate -// that the response itself is an error, not just that its indicating that a +// that the response itself is an error, not just that it's indicating that a // certificate is revoked, unknown, etc. type ResponseError struct { Status ResponseStatus @@ -488,10 +488,6 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon return nil, err } - if len(basicResp.Certificates) > 1 { - return nil, ParseError("OCSP response contains bad number of certificates") - } - if n := len(basicResp.TBSResponseData.Responses); n == 0 || cert == nil && n > 1 { return nil, ParseError("OCSP response contains bad number of responses") } @@ -544,6 +540,13 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon } if len(basicResp.Certificates) > 0 { + // Responders should only send a single certificate (if they + // send any) that connects the responder's certificate to the + // original issuer. We accept responses with multiple + // certificates due to a number responders sending them[1], but + // ignore all but the first. + // + // [1] https://github.com/golang/go/issues/21527 ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes) if err != nil { return nil, err diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go index def4caba..a9437dc1 100644 --- a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go +++ b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go @@ -13,6 +13,7 @@ import ( "bufio" "bytes" "crypto" + "fmt" "hash" "io" "net/textproto" @@ -177,8 +178,9 @@ func Decode(data []byte) (b *Block, rest []byte) { // message. type dashEscaper struct { buffered *bufio.Writer - h hash.Hash + hashers []hash.Hash // one per key in privateKeys hashType crypto.Hash + toHash io.Writer // writes to all the hashes in hashers atBeginningOfLine bool isFirstLine bool @@ -186,8 +188,8 @@ type dashEscaper struct { whitespace []byte byteBuf []byte // a one byte buffer to save allocations - privateKey *packet.PrivateKey - config *packet.Config + privateKeys []*packet.PrivateKey + config *packet.Config } func (d *dashEscaper) Write(data []byte) (n int, err error) { @@ -198,7 +200,7 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { // The final CRLF isn't included in the hash so we have to wait // until this point (the start of the next line) before writing it. if !d.isFirstLine { - d.h.Write(crlf) + d.toHash.Write(crlf) } d.isFirstLine = false } @@ -219,12 +221,12 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { if _, err = d.buffered.Write(dashEscape); err != nil { return } - d.h.Write(d.byteBuf) + d.toHash.Write(d.byteBuf) d.atBeginningOfLine = false } else if b == '\n' { // Nothing to do because we delay writing CRLF to the hash. } else { - d.h.Write(d.byteBuf) + d.toHash.Write(d.byteBuf) d.atBeginningOfLine = false } if err = d.buffered.WriteByte(b); err != nil { @@ -245,13 +247,13 @@ func (d *dashEscaper) Write(data []byte) (n int, err error) { // Any buffered whitespace wasn't at the end of the line so // we need to write it out. if len(d.whitespace) > 0 { - d.h.Write(d.whitespace) + d.toHash.Write(d.whitespace) if _, err = d.buffered.Write(d.whitespace); err != nil { return } d.whitespace = d.whitespace[:0] } - d.h.Write(d.byteBuf) + d.toHash.Write(d.byteBuf) if err = d.buffered.WriteByte(b); err != nil { return } @@ -269,25 +271,29 @@ func (d *dashEscaper) Close() (err error) { return } } - sig := new(packet.Signature) - sig.SigType = packet.SigTypeText - sig.PubKeyAlgo = d.privateKey.PubKeyAlgo - sig.Hash = d.hashType - sig.CreationTime = d.config.Now() - sig.IssuerKeyId = &d.privateKey.KeyId - - if err = sig.Sign(d.h, d.privateKey, d.config); err != nil { - return - } out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil) if err != nil { return } - if err = sig.Serialize(out); err != nil { - return + t := d.config.Now() + for i, k := range d.privateKeys { + sig := new(packet.Signature) + sig.SigType = packet.SigTypeText + sig.PubKeyAlgo = k.PubKeyAlgo + sig.Hash = d.hashType + sig.CreationTime = t + sig.IssuerKeyId = &k.KeyId + + if err = sig.Sign(d.hashers[i], k, d.config); err != nil { + return + } + if err = sig.Serialize(out); err != nil { + return + } } + if err = out.Close(); err != nil { return } @@ -300,8 +306,17 @@ func (d *dashEscaper) Close() (err error) { // Encode returns a WriteCloser which will clear-sign a message with privateKey // and write it to w. If config is nil, sensible defaults are used. func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) { - if privateKey.Encrypted { - return nil, errors.InvalidArgumentError("signing key is encrypted") + return EncodeMulti(w, []*packet.PrivateKey{privateKey}, config) +} + +// EncodeMulti returns a WriteCloser which will clear-sign a message with all the +// private keys indicated and write it to w. If config is nil, sensible defaults +// are used. +func EncodeMulti(w io.Writer, privateKeys []*packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) { + for _, k := range privateKeys { + if k.Encrypted { + return nil, errors.InvalidArgumentError(fmt.Sprintf("signing key %s is encrypted", k.KeyIdString())) + } } hashType := config.Hash() @@ -313,7 +328,14 @@ func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) ( if !hashType.Available() { return nil, errors.UnsupportedError("unsupported hash type: " + strconv.Itoa(int(hashType))) } - h := hashType.New() + var hashers []hash.Hash + var ws []io.Writer + for range privateKeys { + h := hashType.New() + hashers = append(hashers, h) + ws = append(ws, h) + } + toHash := io.MultiWriter(ws...) buffered := bufio.NewWriter(w) // start has a \n at the beginning that we don't want here. @@ -338,16 +360,17 @@ func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) ( plaintext = &dashEscaper{ buffered: buffered, - h: h, + hashers: hashers, hashType: hashType, + toHash: toHash, atBeginningOfLine: true, isFirstLine: true, byteBuf: make([]byte, 1), - privateKey: privateKey, - config: config, + privateKeys: privateKeys, + config: config, } return diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go index 2c094807..96f5d781 100644 --- a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go +++ b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go @@ -6,8 +6,11 @@ package clearsign import ( "bytes" - "golang.org/x/crypto/openpgp" + "fmt" "testing" + + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/packet" ) func testParse(t *testing.T, input []byte, expected, expectedPlaintext string) { @@ -125,6 +128,71 @@ func TestSigning(t *testing.T) { } } +// We use this to make test keys, so that they aren't all the same. +type quickRand byte + +func (qr *quickRand) Read(p []byte) (int, error) { + for i := range p { + p[i] = byte(*qr) + } + *qr++ + return len(p), nil +} + +func TestMultiSign(t *testing.T) { + zero := quickRand(0) + config := packet.Config{Rand: &zero} + + for nKeys := 0; nKeys < 4; nKeys++ { + nextTest: + for nExtra := 0; nExtra < 4; nExtra++ { + var signKeys []*packet.PrivateKey + var verifyKeys openpgp.EntityList + + desc := fmt.Sprintf("%d keys; %d of which will be used to verify", nKeys+nExtra, nKeys) + for i := 0; i < nKeys+nExtra; i++ { + e, err := openpgp.NewEntity("name", "comment", "email", &config) + if err != nil { + t.Errorf("cannot create key: %v", err) + continue nextTest + } + if i < nKeys { + verifyKeys = append(verifyKeys, e) + } + signKeys = append(signKeys, e.PrivateKey) + } + + input := []byte("this is random text\r\n4 17") + var output bytes.Buffer + w, err := EncodeMulti(&output, signKeys, nil) + if err != nil { + t.Errorf("EncodeMulti (%s) failed: %v", desc, err) + } + if _, err := w.Write(input); err != nil { + t.Errorf("Write(%q) to signer (%s) failed: %v", string(input), desc, err) + } + if err := w.Close(); err != nil { + t.Errorf("Close() of signer (%s) failed: %v", desc, err) + } + + block, _ := Decode(output.Bytes()) + if string(block.Bytes) != string(input) { + t.Errorf("Inline data didn't match original; got %q want %q", string(block.Bytes), string(input)) + } + _, err = openpgp.CheckDetachedSignature(verifyKeys, bytes.NewReader(block.Bytes), block.ArmoredSignature.Body) + if nKeys == 0 { + if err == nil { + t.Errorf("verifying inline (%s) succeeded; want failure", desc) + } + } else { + if err != nil { + t.Errorf("verifying inline (%s) failed (%v); want success", desc, err) + } + } + } + } +} + var clearsignInput = []byte(` ;lasjlkfdsa diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go index fd582a89..3e251860 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys.go +++ b/vendor/golang.org/x/crypto/openpgp/keys.go @@ -333,7 +333,6 @@ func ReadEntity(packets *packet.Reader) (*Entity, error) { return nil, errors.StructuralError("primary key cannot be used for signatures") } - var current *Identity var revocations []*packet.Signature EachPacket: for { @@ -346,32 +345,8 @@ EachPacket: switch pkt := p.(type) { case *packet.UserId: - current = new(Identity) - current.Name = pkt.Id - current.UserId = pkt - e.Identities[pkt.Id] = current - - for { - p, err = packets.Next() - if err == io.EOF { - return nil, io.ErrUnexpectedEOF - } else if err != nil { - return nil, err - } - - sig, ok := p.(*packet.Signature) - if !ok { - return nil, errors.StructuralError("user ID packet not followed by self-signature") - } - - if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { - if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { - return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error()) - } - current.SelfSignature = sig - break - } - current.Signatures = append(current.Signatures, sig) + if err := addUserID(e, packets, pkt); err != nil { + return nil, err } case *packet.Signature: if pkt.SigType == packet.SigTypeKeyRevocation { @@ -380,11 +355,9 @@ EachPacket: // TODO: RFC4880 5.2.1 permits signatures // directly on keys (eg. to bind additional // revocation keys). - } else if current == nil { - return nil, errors.StructuralError("signature packet found before user id packet") - } else { - current.Signatures = append(current.Signatures, pkt) } + // Else, ignoring the signature as it does not follow anything + // we would know to attach it to. case *packet.PrivateKey: if pkt.IsSubkey == false { packets.Unread(p) @@ -425,33 +398,105 @@ EachPacket: return e, nil } +func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error { + // Make a new Identity object, that we might wind up throwing away. + // We'll only add it if we get a valid self-signature over this + // userID. + identity := new(Identity) + identity.Name = pkt.Id + identity.UserId = pkt + + for { + p, err := packets.Next() + if err == io.EOF { + break + } else if err != nil { + return err + } + + sig, ok := p.(*packet.Signature) + if !ok { + packets.Unread(p) + break + } + + if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId { + if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil { + return errors.StructuralError("user ID self-signature invalid: " + err.Error()) + } + identity.SelfSignature = sig + e.Identities[pkt.Id] = identity + } else { + identity.Signatures = append(identity.Signatures, sig) + } + } + + return nil +} + func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error { var subKey Subkey subKey.PublicKey = pub subKey.PrivateKey = priv - p, err := packets.Next() - if err == io.EOF { - return io.ErrUnexpectedEOF + + for { + p, err := packets.Next() + if err == io.EOF { + break + } else if err != nil { + return errors.StructuralError("subkey signature invalid: " + err.Error()) + } + + sig, ok := p.(*packet.Signature) + if !ok { + packets.Unread(p) + break + } + + if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation { + return errors.StructuralError("subkey signature with wrong type") + } + + if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil { + return errors.StructuralError("subkey signature invalid: " + err.Error()) + } + + switch sig.SigType { + case packet.SigTypeSubkeyRevocation: + subKey.Sig = sig + case packet.SigTypeSubkeyBinding: + + if shouldReplaceSubkeySig(subKey.Sig, sig) { + subKey.Sig = sig + } + } } - if err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } - var ok bool - subKey.Sig, ok = p.(*packet.Signature) - if !ok { + + if subKey.Sig == nil { return errors.StructuralError("subkey packet not followed by signature") } - if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation { - return errors.StructuralError("subkey signature with wrong type") - } - err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig) - if err != nil { - return errors.StructuralError("subkey signature invalid: " + err.Error()) - } + e.Subkeys = append(e.Subkeys, subKey) + return nil } +func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool { + if potentialNewSig == nil { + return false + } + + if existingSig == nil { + return true + } + + if existingSig.SigType == packet.SigTypeSubkeyRevocation { + return false // never override a revocation signature + } + + return potentialNewSig.CreationTime.After(existingSig.CreationTime) +} + const defaultRSAKeyBits = 2048 // NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a @@ -500,6 +545,10 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err IssuerKeyId: &e.PrimaryKey.KeyId, }, } + err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config) + if err != nil { + return nil, err + } // If the user passes in a DefaultHash via packet.Config, // set the PreferredHash for the SelfSignature. @@ -529,13 +578,16 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err } e.Subkeys[0].PublicKey.IsSubkey = true e.Subkeys[0].PrivateKey.IsSubkey = true - + err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config) + if err != nil { + return nil, err + } return e, nil } -// SerializePrivate serializes an Entity, including private key material, to -// the given Writer. For now, it must only be used on an Entity returned from -// NewEntity. +// SerializePrivate serializes an Entity, including private key material, but +// excluding signatures from other entities, to the given Writer. +// Identities and subkeys are re-signed in case they changed since NewEntry. // If config is nil, sensible defaults will be used. func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) { err = e.PrivateKey.Serialize(w) @@ -573,8 +625,8 @@ func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error return nil } -// Serialize writes the public part of the given Entity to w. (No private -// key material will be output). +// Serialize writes the public part of the given Entity to w, including +// signatures from other entities. No private key material will be output. func (e *Entity) Serialize(w io.Writer) error { err := e.PrimaryKey.Serialize(w) if err != nil { diff --git a/vendor/golang.org/x/crypto/openpgp/keys_data_test.go b/vendor/golang.org/x/crypto/openpgp/keys_data_test.go new file mode 100644 index 00000000..7779bd97 --- /dev/null +++ b/vendor/golang.org/x/crypto/openpgp/keys_data_test.go @@ -0,0 +1,200 @@ +package openpgp + +const expiringKeyHex = "988d0451d1ec5d010400ba3385721f2dc3f4ab096b2ee867ab77213f0a27a8538441c35d2fa225b08798a1439a66a5150e6bdc3f40f5d28d588c712394c632b6299f77db8c0d48d37903fb72ebd794d61be6aa774688839e5fdecfe06b2684cc115d240c98c66cb1ef22ae84e3aa0c2b0c28665c1e7d4d044e7f270706193f5223c8d44e0d70b7b8da830011010001b40f4578706972792074657374206b657988be041301020028050251d1ec5d021b03050900278d00060b090807030206150802090a0b0416020301021e01021780000a091072589ad75e237d8c033503fd10506d72837834eb7f994117740723adc39227104b0d326a1161871c0b415d25b4aedef946ca77ea4c05af9c22b32cf98be86ab890111fced1ee3f75e87b7cc3c00dc63bbc85dfab91c0dc2ad9de2c4d13a34659333a85c6acc1a669c5e1d6cecb0cf1e56c10e72d855ae177ddc9e766f9b2dda57ccbb75f57156438bbdb4e42b88d0451d1ec5d0104009c64906559866c5cb61578f5846a94fcee142a489c9b41e67b12bb54cfe86eb9bc8566460f9a720cb00d6526fbccfd4f552071a8e3f7744b1882d01036d811ee5a3fb91a1c568055758f43ba5d2c6a9676b012f3a1a89e47bbf624f1ad571b208f3cc6224eb378f1645dd3d47584463f9eadeacfd1ce6f813064fbfdcc4b5a53001101000188a504180102000f021b0c050251d1f06b050900093e89000a091072589ad75e237d8c20e00400ab8310a41461425b37889c4da28129b5fae6084fafbc0a47dd1adc74a264c6e9c9cc125f40462ee1433072a58384daef88c961c390ed06426a81b464a53194c4e291ddd7e2e2ba3efced01537d713bd111f48437bde2363446200995e8e0d4e528dda377fd1e8f8ede9c8e2198b393bd86852ce7457a7e3daf74d510461a5b77b88d0451d1ece8010400b3a519f83ab0010307e83bca895170acce8964a044190a2b368892f7a244758d9fc193482648acb1fb9780d28cc22d171931f38bb40279389fc9bf2110876d4f3db4fcfb13f22f7083877fe56592b3b65251312c36f83ffcb6d313c6a17f197dd471f0712aad15a8537b435a92471ba2e5b0c72a6c72536c3b567c558d7b6051001101000188a504180102000f021b0c050251d1f07b050900279091000a091072589ad75e237d8ce69e03fe286026afacf7c97ee20673864d4459a2240b5655219950643c7dba0ac384b1d4359c67805b21d98211f7b09c2a0ccf6410c8c04d4ff4a51293725d8d6570d9d8bb0e10c07d22357caeb49626df99c180be02d77d1fe8ed25e7a54481237646083a9f89a11566cd20b9e995b1487c5f9e02aeb434f3a1897cd416dd0a87861838da3e9e" +const subkeyUsageHex = "988d04533a52bc010400d26af43085558f65b9e7dbc90cb9238015259aed5e954637adcfa2181548b2d0b60c65f1f42ec5081cbf1bc0a8aa4900acfb77070837c58f26012fbce297d70afe96e759ad63531f0037538e70dbf8e384569b9720d99d8eb39d8d0a2947233ed242436cb6ac7dfe74123354b3d0119b5c235d3dd9c9d6c004f8ffaf67ad8583001101000188b7041f010200210502533b8552170c8001ce094aa433f7040bb2ddf0be3893cb843d0fe70c020700000a0910a42704b92866382aa98404009d63d916a27543da4221c60087c33f1c44bec9998c5438018ed370cca4962876c748e94b73eb39c58eb698063f3fd6346d58dd2a11c0247934c4a9d71f24754f7468f96fb24c3e791dd2392b62f626148ad724189498cbf993db2df7c0cdc2d677c35da0f16cb16c9ce7c33b4de65a4a91b1d21a130ae9cc26067718910ef8e2b417556d627261203c756d627261407379642e65642e61753e88b80413010200220502533a52bc021b03060b090807030206150802090a0b0416020301021e01021780000a0910a42704b92866382a47840400c0c2bd04f5fca586de408b395b3c280a278259c93eaaa8b79a53b97003f8ed502a8a00446dd9947fb462677e4fcac0dac2f0701847d15130aadb6cd9e0705ea0cf5f92f129136c7be21a718d46c8e641eb7f044f2adae573e11ae423a0a9ca51324f03a8a2f34b91fa40c3cc764bee4dccadedb54c768ba0469b683ea53f1c29b88d04533a52bc01040099c92a5d6f8b744224da27bc2369127c35269b58bec179de6bbc038f749344222f85a31933224f26b70243c4e4b2d242f0c4777eaef7b5502f9dad6d8bf3aaeb471210674b74de2d7078af497d55f5cdad97c7bedfbc1b41e8065a97c9c3d344b21fc81d27723af8e374bc595da26ea242dccb6ae497be26eea57e563ed517e90011010001889f0418010200090502533a52bc021b0c000a0910a42704b92866382afa1403ff70284c2de8a043ff51d8d29772602fa98009b7861c540535f874f2c230af8caf5638151a636b21f8255003997ccd29747fdd06777bb24f9593bd7d98a3e887689bf902f999915fcc94625ae487e5d13e6616f89090ebc4fdc7eb5cad8943e4056995bb61c6af37f8043016876a958ec7ebf39c43d20d53b7f546cfa83e8d2604b88d04533b8283010400c0b529316dbdf58b4c54461e7e669dc11c09eb7f73819f178ccd4177b9182b91d138605fcf1e463262fabefa73f94a52b5e15d1904635541c7ea540f07050ce0fb51b73e6f88644cec86e91107c957a114f69554548a85295d2b70bd0b203992f76eb5d493d86d9eabcaa7ef3fc7db7e458438db3fcdb0ca1cc97c638439a9170011010001889f0418010200090502533b8283021b0c000a0910a42704b92866382adc6d0400cfff6258485a21675adb7a811c3e19ebca18851533f75a7ba317950b9997fda8d1a4c8c76505c08c04b6c2cc31dc704d33da36a21273f2b388a1a706f7c3378b66d887197a525936ed9a69acb57fe7f718133da85ec742001c5d1864e9c6c8ea1b94f1c3759cebfd93b18606066c063a63be86085b7e37bdbc65f9a915bf084bb901a204533b85cd110400aed3d2c52af2b38b5b67904b0ef73d6dd7aef86adb770e2b153cd22489654dcc91730892087bb9856ae2d9f7ed1eb48f214243fe86bfe87b349ebd7c30e630e49c07b21fdabf78b7a95c8b7f969e97e3d33f2e074c63552ba64a2ded7badc05ce0ea2be6d53485f6900c7860c7aa76560376ce963d7271b9b54638a4028b573f00a0d8854bfcdb04986141568046202192263b9b67350400aaa1049dbc7943141ef590a70dcb028d730371d92ea4863de715f7f0f16d168bd3dc266c2450457d46dcbbf0b071547e5fbee7700a820c3750b236335d8d5848adb3c0da010e998908dfd93d961480084f3aea20b247034f8988eccb5546efaa35a92d0451df3aaf1aee5aa36a4c4d462c760ecd9cebcabfbe1412b1f21450f203fd126687cd486496e971a87fd9e1a8a765fe654baa219a6871ab97768596ab05c26c1aeea8f1a2c72395a58dbc12ef9640d2b95784e974a4d2d5a9b17c25fedacfe551bda52602de8f6d2e48443f5dd1a2a2a8e6a5e70ecdb88cd6e766ad9745c7ee91d78cc55c3d06536b49c3fee6c3d0b6ff0fb2bf13a314f57c953b8f4d93bf88e70418010200090502533b85cd021b0200520910a42704b92866382a47200419110200060502533b85cd000a091042ce2c64bc0ba99214b2009e26b26852c8b13b10c35768e40e78fbbb48bd084100a0c79d9ea0844fa5853dd3c85ff3ecae6f2c9dd6c557aa04008bbbc964cd65b9b8299d4ebf31f41cc7264b8cf33a00e82c5af022331fac79efc9563a822497ba012953cefe2629f1242fcdcb911dbb2315985bab060bfd58261ace3c654bdbbe2e8ed27a46e836490145c86dc7bae15c011f7e1ffc33730109b9338cd9f483e7cef3d2f396aab5bd80efb6646d7e778270ee99d934d187dd98" +const revokedKeyHex = "988d045331ce82010400c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be10011010001889f04200102000905025331d0e3021d03000a0910a401d9f09a34f7c042aa040086631196405b7e6af71026b88e98012eab44aa9849f6ef3fa930c7c9f23deaedba9db1538830f8652fb7648ec3fcade8dbcbf9eaf428e83c6cbcc272201bfe2fbb90d41963397a7c0637a1a9d9448ce695d9790db2dc95433ad7be19eb3de72dacf1d6db82c3644c13eae2a3d072b99bb341debba012c5ce4006a7d34a1f4b94b444526567205265766f6b657220283c52656727732022424d204261726973746122204b657920262530305c303e5c29203c72656740626d626172697374612e636f2e61753e88b704130102002205025331ce82021b03060b090807030206150802090a0b0416020301021e01021780000a0910a401d9f09a34f7c0019c03f75edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56889c04100102000605025331cfb5000a0910fe9645554e8266b64b4303fc084075396674fb6f778d302ac07cef6bc0b5d07b66b2004c44aef711cbac79617ef06d836b4957522d8772dd94bf41a2f4ac8b1ee6d70c57503f837445a74765a076d07b829b8111fc2a918423ddb817ead7ca2a613ef0bfb9c6b3562aec6c3cf3c75ef3031d81d95f6563e4cdcc9960bcb386c5d757b104fcca5fe11fc709df884604101102000605025331cfe7000a09107b15a67f0b3ddc0317f6009e360beea58f29c1d963a22b962b80788c3fa6c84e009d148cfde6b351469b8eae91187eff07ad9d08fcaab88d045331ce820104009f25e20a42b904f3fa555530fe5c46737cf7bd076c35a2a0d22b11f7e0b61a69320b768f4a80fe13980ce380d1cfc4a0cd8fbe2d2e2ef85416668b77208baa65bf973fe8e500e78cc310d7c8705cdb34328bf80e24f0385fce5845c33bc7943cf6b11b02348a23da0bf6428e57c05135f2dc6bd7c1ce325d666d5a5fd2fd5e410011010001889f04180102000905025331ce82021b0c000a0910a401d9f09a34f7c0418003fe34feafcbeaef348a800a0d908a7a6809cc7304017d820f70f0474d5e23cb17e38b67dc6dca282c6ca00961f4ec9edf2738d0f087b1d81e4871ef08e1798010863afb4eac4c44a376cb343be929c5be66a78cfd4456ae9ec6a99d97f4e1c3ff3583351db2147a65c0acef5c003fb544ab3a2e2dc4d43646f58b811a6c3a369d1f" +const revokedSubkeyHex = "988d04533121f6010400aefc803a3e4bb1a61c86e8a86d2726c6a43e0079e9f2713f1fa017e9854c83877f4aced8e331d675c67ea83ddab80aacbfa0b9040bb12d96f5a3d6be09455e2a76546cbd21677537db941cab710216b6d24ec277ee0bd65b910f416737ed120f6b93a9d3b306245c8cfd8394606fdb462e5cf43c551438d2864506c63367fc890011010001b41d416c696365203c616c69636540626d626172697374612e636f2e61753e88bb041301020025021b03060b090807030206150802090a0b0416020301021e01021780050253312798021901000a09104ef7e4beccde97f015a803ff5448437780f63263b0df8442a995e7f76c221351a51edd06f2063d8166cf3157aada4923dfc44aa0f2a6a4da5cf83b7fe722ba8ab416c976e77c6b5682e7f1069026673bd0de56ba06fd5d7a9f177607f277d9b55ff940a638c3e68525c67517e2b3d976899b93ca267f705b3e5efad7d61220e96b618a4497eab8d04403d23f8846041011020006050253312910000a09107b15a67f0b3ddc03d96e009f50b6365d86c4be5d5e9d0ea42d5e56f5794c617700a0ab274e19c2827780016d23417ce89e0a2c0d987d889c04100102000605025331cf7a000a0910a401d9f09a34f7c0ee970400aca292f213041c9f3b3fc49148cbda9d84afee6183c8dd6c5ff2600b29482db5fecd4303797be1ee6d544a20a858080fec43412061c9a71fae4039fd58013b4ae341273e6c66ad4c7cdd9e68245bedb260562e7b166f2461a1032f2b38c0e0e5715fb3d1656979e052b55ca827a76f872b78a9fdae64bc298170bfcebedc1271b41a416c696365203c616c696365407379646973702e6f722e61753e88b804130102002205025331278b021b03060b090807030206150802090a0b0416020301021e01021780000a09104ef7e4beccde97f06a7003fa03c3af68d272ebc1fa08aa72a03b02189c26496a2833d90450801c4e42c5b5f51ad96ce2d2c9cef4b7c02a6a2fcf1412d6a2d486098eb762f5010a201819c17fd2888aec8eda20c65a3b75744de7ee5cc8ac7bfc470cbe3cb982720405a27a3c6a8c229cfe36905f881b02ed5680f6a8f05866efb9d6c5844897e631deb949ca8846041011020006050253312910000a09107b15a67f0b3ddc0347bc009f7fa35db59147469eb6f2c5aaf6428accb138b22800a0caa2f5f0874bacc5909c652a57a31beda65eddd5889c04100102000605025331cf7a000a0910a401d9f09a34f7c0316403ff46f2a5c101256627f16384d34a38fb47a6c88ba60506843e532d91614339fccae5f884a5741e7582ffaf292ba38ee10a270a05f139bde3814b6a077e8cd2db0f105ebea2a83af70d385f13b507fac2ad93ff79d84950328bb86f3074745a8b7f9b64990fb142e2a12976e27e8d09a28dc5621f957ac49091116da410ac3cbde1b88d04533121f6010400cbd785b56905e4192e2fb62a720727d43c4fa487821203cf72138b884b78b701093243e1d8c92a0248a6c0203a5a88693da34af357499abacaf4b3309c640797d03093870a323b4b6f37865f6eaa2838148a67df4735d43a90ca87942554cdf1c4a751b1e75f9fd4ce4e97e278d6c1c7ed59d33441df7d084f3f02beb68896c70011010001889f0418010200090502533121f6021b0c000a09104ef7e4beccde97f0b98b03fc0a5ccf6a372995835a2f5da33b282a7d612c0ab2a97f59cf9fff73e9110981aac2858c41399afa29624a7fd8a0add11654e3d882c0fd199e161bdad65e5e2548f7b68a437ea64293db1246e3011cbb94dc1bcdeaf0f2539bd88ff16d95547144d97cead6a8c5927660a91e6db0d16eb36b7b49a3525b54d1644e65599b032b7eb901a204533127a0110400bd3edaa09eff9809c4edc2c2a0ebe52e53c50a19c1e49ab78e6167bf61473bb08f2050d78a5cbbc6ed66aff7b42cd503f16b4a0b99fa1609681fca9b7ce2bbb1a5b3864d6cdda4d7ef7849d156d534dea30fb0efb9e4cf8959a2b2ce623905882d5430b995a15c3b9fe92906086788b891002924f94abe139b42cbbfaaabe42f00a0b65dc1a1ad27d798adbcb5b5ad02d2688c89477b03ff4eebb6f7b15a73b96a96bed201c0e5e4ea27e4c6e2dd1005b94d4b90137a5b1cf5e01c6226c070c4cc999938101578877ee76d296b9aab8246d57049caacf489e80a3f40589cade790a020b1ac146d6f7a6241184b8c7fcde680eae3188f5dcbe846d7f7bdad34f6fcfca08413e19c1d5df83fc7c7c627d493492e009c2f52a80400a2fe82de87136fd2e8845888c4431b032ba29d9a29a804277e31002a8201fb8591a3e55c7a0d0881496caf8b9fb07544a5a4879291d0dc026a0ea9e5bd88eb4aa4947bbd694b25012e208a250d65ddc6f1eea59d3aed3b4ec15fcab85e2afaa23a40ab1ef9ce3e11e1bc1c34a0e758e7aa64deb8739276df0af7d4121f834a9b88e70418010200090502533127a0021b02005209104ef7e4beccde97f047200419110200060502533127a0000a0910dbce4ee19529437fe045009c0b32f5ead48ee8a7e98fac0dea3d3e6c0e2c552500a0ad71fadc5007cfaf842d9b7db3335a8cdad15d3d1a6404009b08e2c68fe8f3b45c1bb72a4b3278cdf3012aa0f229883ad74aa1f6000bb90b18301b2f85372ca5d6b9bf478d235b733b1b197d19ccca48e9daf8e890cb64546b4ce1b178faccfff07003c172a2d4f5ebaba9f57153955f3f61a9b80a4f5cb959908f8b211b03b7026a8a82fc612bfedd3794969bcf458c4ce92be215a1176ab88d045331d144010400a5063000c5aaf34953c1aa3bfc95045b3aab9882b9a8027fecfe2142dc6b47ba8aca667399990244d513dd0504716908c17d92c65e74219e004f7b83fc125e575dd58efec3ab6dd22e3580106998523dea42ec75bf9aa111734c82df54630bebdff20fe981cfc36c76f865eb1c2fb62c9e85bc3a6e5015a361a2eb1c8431578d0011010001889f04280102000905025331d433021d03000a09104ef7e4beccde97f02e5503ff5e0630d1b65291f4882b6d40a29da4616bb5088717d469fbcc3648b8276de04a04988b1f1b9f3e18f52265c1f8b6c85861691c1a6b8a3a25a1809a0b32ad330aec5667cb4262f4450649184e8113849b05e5ad06a316ea80c001e8e71838190339a6e48bbde30647bcf245134b9a97fa875c1d83a9862cae87ffd7e2c4ce3a1b89013d04180102000905025331d144021b0200a809104ef7e4beccde97f09d2004190102000605025331d144000a0910677815e371c2fd23522203fe22ab62b8e7a151383cea3edd3a12995693911426f8ccf125e1f6426388c0010f88d9ca7da2224aee8d1c12135998640c5e1813d55a93df472faae75bef858457248db41b4505827590aeccf6f9eb646da7f980655dd3050c6897feddddaca90676dee856d66db8923477d251712bb9b3186b4d0114daf7d6b59272b53218dd1da94a03ff64006fcbe71211e5daecd9961fba66cdb6de3f914882c58ba5beddeba7dcb950c1156d7fba18c19ea880dccc800eae335deec34e3b84ac75ffa24864f782f87815cda1c0f634b3dd2fa67cea30811d21723d21d9551fa12ccbcfa62b6d3a15d01307b99925707992556d50065505b090aadb8579083a20fe65bd2a270da9b011" + +const missingCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Charset: UTF-8 + +mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY +ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG +zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54 +QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ +QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo +9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu +Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/ +dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R +JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL +ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew +RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW +/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu +yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAJcXQeP+NmuciE99YcJoffxv +2gVLU4ZXBNHEaP0mgaJ1+tmMD089vUQAcyGRvw8jfsNsVZQIOAuRxY94aHQhIRHR +bUzBN28ofo/AJJtfx62C15xt6fDKRV6HXYqAiygrHIpEoRLyiN69iScUsjIJeyFL +C8wa72e8pSL6dkHoaV1N9ZH/xmrJ+k0vsgkQaAh9CzYufncDxcwkoP+aOlGtX1gP +WwWoIbz0JwLEMPHBWvDDXQcQPQTYQyj+LGC9U6f9VZHN25E94subM1MjuT9OhN9Y +MLfWaaIc5WyhLFyQKW2Upofn9wSFi8ubyBnv640Dfd0rVmaWv7LNTZpoZ/GbJAMA +EQEAAYkBHwQYAQIACQUCU5ygeQIbAgAKCRDt1A0FCB6SP0zCB/sEzaVR38vpx+OQ +MMynCBJrakiqDmUZv9xtplY7zsHSQjpd6xGflbU2n+iX99Q+nav0ETQZifNUEd4N +1ljDGQejcTyKD6Pkg6wBL3x9/RJye7Zszazm4+toJXZ8xJ3800+BtaPoI39akYJm ++ijzbskvN0v/j5GOFJwQO0pPRAFtdHqRs9Kf4YanxhedB4dIUblzlIJuKsxFit6N +lgGRblagG3Vv2eBszbxzPbJjHCgVLR3RmrVezKOsZjr/2i7X+xLWIR0uD3IN1qOW +CXQxLBizEEmSNVNxsp7KPGTLnqO3bPtqFirxS9PJLIMPTPLNBY7ZYuPNTMqVIUWF +4artDmrG +=7FfJ +-----END PGP PUBLIC KEY BLOCK-----` + +const invalidCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY +ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG +zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54 +QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ +QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo +9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu +Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/ +dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R +JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL +ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew +RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW +/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu +yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAIINDqlj7X6jYKc6DjwrOkjQ +UIRWbQQar0LwmNilehmt70g5DCL1SYm9q4LcgJJ2Nhxj0/5qqsYib50OSWMcKeEe +iRXpXzv1ObpcQtI5ithp0gR53YPXBib80t3bUzomQ5UyZqAAHzMp3BKC54/vUrSK +FeRaxDzNLrCeyI00+LHNUtwghAqHvdNcsIf8VRumK8oTm3RmDh0TyjASWYbrt9c8 +R1Um3zuoACOVy+mEIgIzsfHq0u7dwYwJB5+KeM7ZLx+HGIYdUYzHuUE1sLwVoELh ++SHIGHI1HDicOjzqgajShuIjj5hZTyQySVprrsLKiXS6NEwHAP20+XjayJ/R3tEA +EQEAAYkCPgQYAQIBKAUCU5ygeQIbAsBdIAQZAQIABgUCU5ygeQAKCRCpVlnFZmhO +52RJB/9uD1MSa0wjY6tHOIgquZcP3bHBvHmrHNMw9HR2wRCMO91ZkhrpdS3ZHtgb +u3/55etj0FdvDo1tb8P8FGSVtO5Vcwf5APM8sbbqoi8L951Q3i7qt847lfhu6sMl +w0LWFvPTOLHrliZHItPRjOltS1WAWfr2jUYhsU9ytaDAJmvf9DujxEOsN5G1YJep +54JCKVCkM/y585Zcnn+yxk/XwqoNQ0/iJUT9qRrZWvoeasxhl1PQcwihCwss44A+ +YXaAt3hbk+6LEQuZoYS73yR3WHj+42tfm7YxRGeubXfgCEz/brETEWXMh4pe0vCL +bfWrmfSPq2rDegYcAybxRQz0lF8PAAoJEO3UDQUIHpI/exkH/0vQfdHA8g/N4T6E +i6b1CUVBAkvtdJpCATZjWPhXmShOw62gkDw306vHPilL4SCvEEi4KzG72zkp6VsB +DSRcpxCwT4mHue+duiy53/aRMtSJ+vDfiV1Vhq+3sWAck/yUtfDU9/u4eFaiNok1 +8/Gd7reyuZt5CiJnpdPpjCwelK21l2w7sHAnJF55ITXdOxI8oG3BRKufz0z5lyDY +s2tXYmhhQIggdgelN8LbcMhWs/PBbtUr6uZlNJG2lW1yscD4aI529VjwJlCeo745 +U7pO4eF05VViUJ2mmfoivL3tkhoTUWhx8xs8xCUcCg8DoEoSIhxtOmoTPR22Z9BL +6LCg2mg= +=Dhm4 +-----END PGP PUBLIC KEY BLOCK-----` + +const goodCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mI0EVUqeVwEEAMufHRrMPWK3gyvi0O0tABCs/oON9zV9KDZlr1a1M91ShCSFwCPo +7r80PxdWVWcj0V5h50/CJYtpN3eE/mUIgW2z1uDYQF1OzrQ8ubrksfsJvpAhENom +lTQEppv9mV8qhcM278teb7TX0pgrUHLYF5CfPdp1L957JLLXoQR/lwLVABEBAAG0 +E2dvb2Qtc2lnbmluZy1zdWJrZXmIuAQTAQIAIgUCVUqeVwIbAwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AACgkQNRjL95IRWP69XQQAlH6+eyXJN4DZTLX78KGjHrsw +6FCvxxClEPtPUjcJy/1KCRQmtLAt9PbbA78dvgzjDeZMZqRAwdjyJhjyg/fkU2OH +7wq4ktjUu+dLcOBb+BFMEY+YjKZhf6EJuVfxoTVr5f82XNPbYHfTho9/OABKH6kv +X70PaKZhbwnwij8Nts65AaIEVUqftREEAJ3WxZfqAX0bTDbQPf2CMT2IVMGDfhK7 +GyubOZgDFFjwUJQvHNvsrbeGLZ0xOBumLINyPO1amIfTgJNm1iiWFWfmnHReGcDl +y5mpYG60Mb79Whdcer7CMm3AqYh/dW4g6IB02NwZMKoUHo3PXmFLxMKXnWyJ0clw +R0LI/Qn509yXAKDh1SO20rqrBM+EAP2c5bfI98kyNwQAi3buu94qo3RR1ZbvfxgW +CKXDVm6N99jdZGNK7FbRifXqzJJDLcXZKLnstnC4Sd3uyfyf1uFhmDLIQRryn5m+ +LBYHfDBPN3kdm7bsZDDq9GbTHiFZUfm/tChVKXWxkhpAmHhU/tH6GGzNSMXuIWSO +aOz3Rqq0ED4NXyNKjdF9MiwD/i83S0ZBc0LmJYt4Z10jtH2B6tYdqnAK29uQaadx +yZCX2scE09UIm32/w7pV77CKr1Cp/4OzAXS1tmFzQ+bX7DR+Gl8t4wxr57VeEMvl +BGw4Vjh3X8//m3xynxycQU18Q1zJ6PkiMyPw2owZ/nss3hpSRKFJsxMLhW3fKmKr +Ey2KiOcEGAECAAkFAlVKn7UCGwIAUgkQNRjL95IRWP5HIAQZEQIABgUCVUqftQAK +CRD98VjDN10SqkWrAKDTpEY8D8HC02E/KVC5YUI01B30wgCgurpILm20kXEDCeHp +C5pygfXw1DJrhAP+NyPJ4um/bU1I+rXaHHJYroYJs8YSweiNcwiHDQn0Engh/mVZ +SqLHvbKh2dL/RXymC3+rjPvQf5cup9bPxNMa6WagdYBNAfzWGtkVISeaQW+cTEp/ +MtgVijRGXR/lGLGETPg2X3Afwn9N9bLMBkBprKgbBqU7lpaoPupxT61bL70= +=vtbN +-----END PGP PUBLIC KEY BLOCK-----` + +const revokedUserIDKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFsgO5EBCADhREPmcjsPkXe1z7ctvyWL0S7oa9JaoGZ9oPDHFDlQxd0qlX2e +DZJZDg0qYvVixmaULIulApq1puEsaJCn3lHUbHlb4PYKwLEywYXM28JN91KtLsz/ +uaEX2KC5WqeP40utmzkNLq+oRX/xnRMgwbO7yUNVG2UlEa6eI+xOXO3YtLdmJMBW +ClQ066ZnOIzEo1JxnIwha1CDBMWLLfOLrg6l8InUqaXbtEBbnaIYO6fXVXELUjkx +nmk7t/QOk0tXCy8muH9UDqJkwDUESY2l79XwBAcx9riX8vY7vwC34pm22fAUVLCJ +x1SJx0J8bkeNp38jKM2Zd9SUQqSbfBopQ4pPABEBAAG0I0dvbGFuZyBHb3BoZXIg +PG5vLXJlcGx5QGdvbGFuZy5jb20+iQFUBBMBCgA+FiEE5Ik5JLcNx6l6rZfw1oFy +9I6cUoMFAlsgO5ECGwMFCQPCZwAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ +1oFy9I6cUoMIkwf8DNPeD23i4jRwd/pylbvxwZintZl1fSwTJW1xcOa1emXaEtX2 +depuqhP04fjlRQGfsYAQh7X9jOJxAHjTmhqFBi5sD7QvKU00cPFYbJ/JTx0B41bl +aXnSbGhRPh63QtEZL7ACAs+shwvvojJqysx7kyVRu0EW2wqjXdHwR/SJO6nhNBa2 +DXzSiOU/SUA42mmG+5kjF8Aabq9wPwT9wjraHShEweNerNMmOqJExBOy3yFeyDpa +XwEZFzBfOKoxFNkIaVf5GSdIUGhFECkGvBMB935khftmgR8APxdU4BE7XrXexFJU +8RCuPXonm4WQOwTWR0vQg64pb2WKAzZ8HhwTGbQiR29sYW5nIEdvcGhlciA8cmV2 +b2tlZEBnb2xhbmcuY29tPokBNgQwAQoAIBYhBOSJOSS3Dcepeq2X8NaBcvSOnFKD +BQJbIDv3Ah0AAAoJENaBcvSOnFKDfWMIAKhI/Tvu3h8fSUxp/gSAcduT6bC1JttG +0lYQ5ilKB/58lBUA5CO3ZrKDKlzW3M8VEcvohVaqeTMKeoQd5rCZq8KxHn/KvN6N +s85REfXfniCKfAbnGgVXX3kDmZ1g63pkxrFu0fDZjVDXC6vy+I0sGyI/Inro0Pzb +tvn0QCsxjapKK15BtmSrpgHgzVqVg0cUp8vqZeKFxarYbYB2idtGRci4b9tObOK0 +BSTVFy26+I/mrFGaPrySYiy2Kz5NMEcRhjmTxJ8jSwEr2O2sUR0yjbgUAXbTxDVE +/jg5fQZ1ACvBRQnB7LvMHcInbzjyeTM3FazkkSYQD6b97+dkWwb1iWG5AQ0EWyA7 +kQEIALkg04REDZo1JgdYV4x8HJKFS4xAYWbIva1ZPqvDNmZRUbQZR2+gpJGEwn7z +VofGvnOYiGW56AS5j31SFf5kro1+1bZQ5iOONBng08OOo58/l1hRseIIVGB5TGSa +PCdChKKHreJI6hS3mShxH6hdfFtiZuB45rwoaArMMsYcjaezLwKeLc396cpUwwcZ +snLUNd1Xu5EWEF2OdFkZ2a1qYdxBvAYdQf4+1Nr+NRIx1u1NS9c8jp3PuMOkrQEi +bNtc1v6v0Jy52mKLG4y7mC/erIkvkQBYJdxPaP7LZVaPYc3/xskcyijrJ/5ufoD8 +K71/ShtsZUXSQn9jlRaYR0EbojMAEQEAAYkBPAQYAQoAJhYhBOSJOSS3Dcepeq2X +8NaBcvSOnFKDBQJbIDuRAhsMBQkDwmcAAAoJENaBcvSOnFKDkFMIAIt64bVZ8x7+ +TitH1bR4pgcNkaKmgKoZz6FXu80+SnbuEt2NnDyf1cLOSimSTILpwLIuv9Uft5Pb +OraQbYt3xi9yrqdKqGLv80bxqK0NuryNkvh9yyx5WoG1iKqMj9/FjGghuPrRaT4l +QinNAghGVkEy1+aXGFrG2DsOC1FFI51CC2WVTzZ5RwR2GpiNRfESsU1rZAUqf/2V +yJl9bD5R4SUNy8oQmhOxi+gbhD4Ao34e4W0ilibslI/uawvCiOwlu5NGd8zv5n+U +heiQvzkApQup5c+BhH5zFDFdKJ2CBByxw9+7QjMFI/wgLixKuE0Ob2kAokXf7RlB +7qTZOahrETw= +=IKnw +-----END PGP PUBLIC KEY BLOCK-----` + +const keyWithSubKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +mI0EWyKwKQEEALwXhKBnyaaNFeK3ljfc/qn9X/QFw+28EUfgZPHjRmHubuXLE2uR +s3ZoSXY2z7Dkv+NyHYMt8p+X8q5fR7JvUjK2XbPyKoiJVnHINll83yl67DaWfKNL +EjNoO0kIfbXfCkZ7EG6DL+iKtuxniGTcnGT47e+HJSqb/STpLMnWwXjBABEBAAG0 +I0dvbGFuZyBHb3BoZXIgPG5vLXJlcGx5QGdvbGFuZy5jb20+iM4EEwEKADgWIQQ/ +lRafP/p9PytHbwxMvYJsOQdOOAUCWyKwKQIbAwULCQgHAwUVCgkICwUWAgMBAAIe +AQIXgAAKCRBMvYJsOQdOOOsFBAC62mXww8XuqvYLcVOvHkWLT6mhxrQOJXnlfpn7 +2uBV9CMhoG/Ycd43NONsJrB95Apr9TDIqWnVszNbqPCuBhZQSGLdbiDKjxnCWBk0 +69qv4RNtkpOhYB7jK4s8F5oQZqId6JasT/PmJTH92mhBYhhTQr0GYFuPX2UJdkw9 +Sn9C67iNBFsisDUBBAC3A+Yo9lgCnxi/pfskyLrweYif6kIXWLAtLTsM6g/6jt7b +wTrknuCPyTv0QKGXsAEe/cK/Xq3HvX9WfXPGIHc/X56ZIsHQ+RLowbZV/Lhok1IW +FAuQm8axr/by80cRwFnzhfPc/ukkAq2Qyj4hLsGblu6mxeAhzcp8aqmWOO2H9QAR +AQABiLYEKAEKACAWIQQ/lRafP/p9PytHbwxMvYJsOQdOOAUCWyK16gIdAAAKCRBM +vYJsOQdOOB1vA/4u4uLONsE+2GVOyBsHyy7uTdkuxaR9b54A/cz6jT/tzUbeIzgx +22neWhgvIEghnUZd0vEyK9k1wy5vbDlEo6nKzHso32N1QExGr5upRERAxweDxGOj +7luDwNypI7QcifE64lS/JmlnunwRCdRWMKc0Fp+7jtRc5mpwyHN/Suf5RokBagQY +AQoAIBYhBD+VFp8/+n0/K0dvDEy9gmw5B044BQJbIrA1AhsCAL8JEEy9gmw5B044 +tCAEGQEKAB0WIQSNdnkaWY6t62iX336UXbGvYdhXJwUCWyKwNQAKCRCUXbGvYdhX +JxJSA/9fCPHP6sUtGF1o3G1a3yvOUDGr1JWcct9U+QpbCt1mZoNopCNDDQAJvDWl +mvDgHfuogmgNJRjOMznvahbF+wpTXmB7LS0SK412gJzl1fFIpK4bgnhu0TwxNsO1 +8UkCZWqxRMgcNUn9z6XWONK8dgt5JNvHSHrwF4CxxwjL23AAtK+FA/UUoi3U4kbC +0XnSr1Sl+mrzQi1+H7xyMe7zjqe+gGANtskqexHzwWPUJCPZ5qpIa2l8ghiUim6b +4ymJ+N8/T8Yva1FaPEqfMzzqJr8McYFm0URioXJPvOAlRxdHPteZ0qUopt/Jawxl +Xt6B9h1YpeLoJwjwsvbi98UTRs0jXwoY +=3fWu +-----END PGP PUBLIC KEY BLOCK-----` + +const keyWithSubKeyAndBadSelfSigOrder = `-----BEGIN PGP PUBLIC KEY BLOCK----- + +mI0EWyLLDQEEAOqIOpJ/ha1OYAGduu9tS3rBz5vyjbNgJO4sFveEM0mgsHQ0X9/L +plonW+d0gRoO1dhJ8QICjDAc6+cna1DE3tEb5m6JtQ30teLZuqrR398Cf6w7NNVz +r3lrlmnH9JaKRuXl7tZciwyovneBfZVCdtsRZjaLI1uMQCz/BToiYe3DABEBAAG0 +I0dvbGFuZyBHb3BoZXIgPG5vLXJlcGx5QGdvbGFuZy5jb20+iM4EEwEKADgWIQRZ +sixZOfQcZdW0wUqmgmdsv1O9xgUCWyLLDQIbAwULCQgHAwUVCgkICwUWAgMBAAIe +AQIXgAAKCRCmgmdsv1O9xql2A/4pix98NxjhdsXtazA9agpAKeADf9tG4Za27Gj+ +3DCww/E4iP2X35jZimSm/30QRB6j08uGCqd9vXkkJxtOt63y/IpVOtWX6vMWSTUm +k8xKkaYMP0/IzKNJ1qC/qYEUYpwERBKg9Z+k99E2Ql4kRHdxXUHq6OzY79H18Y+s +GdeM/riNBFsiyxsBBAC54Pxg/8ZWaZX1phGdwfe5mek27SOYpC0AxIDCSOdMeQ6G +HPk38pywl1d+S+KmF/F4Tdi+kWro62O4eG2uc/T8JQuRDUhSjX0Qa51gPzJrUOVT +CFyUkiZ/3ZDhtXkgfuso8ua2ChBgR9Ngr4v43tSqa9y6AK7v0qjxD1x+xMrjXQAR +AQABiQFxBBgBCgAmAhsCFiEEWbIsWTn0HGXVtMFKpoJnbL9TvcYFAlsizTIFCQAN +MRcAv7QgBBkBCgAdFiEEJcoVUVJIk5RWj1c/o62jUpRPICQFAlsiyxsACgkQo62j +UpRPICQq5gQApoWIigZxXFoM0uw4uJBS5JFZtirTANvirZV5RhndwHeMN6JttaBS +YnjyA4+n1D+zB2VqliD2QrsX12KJN6rGOehCtEIClQ1Hodo9nC6kMzzAwW1O8bZs +nRJmXV+bsvD4sidLZLjdwOVa3Cxh6pvq4Uur6a7/UYx121hEY0Qx0s8JEKaCZ2y/ +U73GGi0D/i20VW8AWYAPACm2zMlzExKTOAV01YTQH/3vW0WLrOse53WcIVZga6es +HuO4So0SOEAvxKMe5HpRIu2dJxTvd99Bo9xk9xJU0AoFrO0vNCRnL+5y68xMlODK +lEw5/kl0jeaTBp6xX0HDQOEVOpPGUwWV4Ij2EnvfNDXaE1vK1kffiQFrBBgBCgAg +AhsCFiEEWbIsWTn0HGXVtMFKpoJnbL9TvcYFAlsi0AYAv7QgBBkBCgAdFiEEJcoV +UVJIk5RWj1c/o62jUpRPICQFAlsiyxsACgkQo62jUpRPICQq5gQApoWIigZxXFoM +0uw4uJBS5JFZtirTANvirZV5RhndwHeMN6JttaBSYnjyA4+n1D+zB2VqliD2QrsX +12KJN6rGOehCtEIClQ1Hodo9nC6kMzzAwW1O8bZsnRJmXV+bsvD4sidLZLjdwOVa +3Cxh6pvq4Uur6a7/UYx121hEY0Qx0s8JEKaCZ2y/U73GRl0EAJokkXmy4zKDHWWi +wvK9gi2gQgRkVnu2AiONxJb5vjeLhM/07BRmH6K1o+w3fOeEQp4FjXj1eQ5fPSM6 +Hhwx2CTl9SDnPSBMiKXsEFRkmwQ2AAsQZLmQZvKBkLZYeBiwf+IY621eYDhZfo+G +1dh1WoUCyREZsJQg2YoIpWIcvw+a +=bNRo +-----END PGP PUBLIC KEY BLOCK----- +` diff --git a/vendor/golang.org/x/crypto/openpgp/keys_test.go b/vendor/golang.org/x/crypto/openpgp/keys_test.go index 3a155063..0eb1a9ef 100644 --- a/vendor/golang.org/x/crypto/openpgp/keys_test.go +++ b/vendor/golang.org/x/crypto/openpgp/keys_test.go @@ -29,16 +29,16 @@ func TestKeyExpiry(t *testing.T) { // // So this should select the newest, non-expired encryption key. key, _ := entity.encryptionKey(time1) - if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" { - t.Errorf("Expected key 1ABB25A0 at time %s, but got key %s", time1.Format(timeFormat), id) + if id, expected := key.PublicKey.KeyIdShortString(), "96A672F5"; id != expected { + t.Errorf("Expected key %s at time %s, but got key %s", expected, time1.Format(timeFormat), id) } // Once the first encryption subkey has expired, the second should be // selected. time2, _ := time.Parse(timeFormat, "2013-07-09") key, _ = entity.encryptionKey(time2) - if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" { - t.Errorf("Expected key 96A672F5 at time %s, but got key %s", time2.Format(timeFormat), id) + if id, expected := key.PublicKey.KeyIdShortString(), "96A672F5"; id != expected { + t.Errorf("Expected key %s at time %s, but got key %s", expected, time2.Format(timeFormat), id) } // Once all the keys have expired, nothing should be returned. @@ -105,6 +105,33 @@ func TestGoodCrossSignature(t *testing.T) { } } +func TestRevokedUserID(t *testing.T) { + // This key contains 2 UIDs, one of which is revoked: + // [ultimate] (1) Golang Gopher + // [ revoked] (2) Golang Gopher + keys, err := ReadArmoredKeyRing(bytes.NewBufferString(revokedUserIDKey)) + if err != nil { + t.Fatal(err) + } + + if len(keys) != 1 { + t.Fatal("Failed to read key with a revoked user id") + } + + var identities []*Identity + for _, identity := range keys[0].Identities { + identities = append(identities, identity) + } + + if numIdentities, numExpected := len(identities), 1; numIdentities != numExpected { + t.Errorf("obtained %d identities, expected %d", numIdentities, numExpected) + } + + if identityName, expectedName := identities[0].Name, "Golang Gopher "; identityName != expectedName { + t.Errorf("obtained identity %s expected %s", identityName, expectedName) + } +} + // TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission. func TestExternallyRevocableKey(t *testing.T) { kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex)) @@ -153,6 +180,44 @@ func TestKeyRevocation(t *testing.T) { } } +func TestKeyWithRevokedSubKey(t *testing.T) { + // This key contains a revoked sub key: + // pub rsa1024/0x4CBD826C39074E38 2018-06-14 [SC] + // Key fingerprint = 3F95 169F 3FFA 7D3F 2B47 6F0C 4CBD 826C 3907 4E38 + // uid Golang Gopher + // sub rsa1024/0x945DB1AF61D85727 2018-06-14 [S] [revoked: 2018-06-14] + + keys, err := ReadArmoredKeyRing(bytes.NewBufferString(keyWithSubKey)) + if err != nil { + t.Fatal(err) + } + + if len(keys) != 1 { + t.Fatal("Failed to read key with a sub key") + } + + identity := keys[0].Identities["Golang Gopher "] + + // Test for an issue where Subkey Binding Signatures (RFC 4880 5.2.1) were added to the identity + // preceding the Subkey Packet if the Subkey Packet was followed by more than one signature. + // For example, the current key has the following layout: + // PUBKEY UID SELFSIG SUBKEY REV SELFSIG + // The last SELFSIG would be added to the UID's signatures. This is wrong. + if numIdentitySigs, numExpected := len(identity.Signatures), 0; numIdentitySigs != numExpected { + t.Fatalf("got %d identity signatures, expected %d", numIdentitySigs, numExpected) + } + + if numSubKeys, numExpected := len(keys[0].Subkeys), 1; numSubKeys != numExpected { + t.Fatalf("got %d subkeys, expected %d", numSubKeys, numExpected) + } + + subKey := keys[0].Subkeys[0] + if subKey.Sig == nil { + t.Fatalf("subkey signature is nil") + } + +} + func TestSubkeyRevocation(t *testing.T) { kring, err := ReadKeyRing(readerFromHex(revokedSubkeyHex)) if err != nil { @@ -189,6 +254,51 @@ func TestSubkeyRevocation(t *testing.T) { } } +func TestKeyWithSubKeyAndBadSelfSigOrder(t *testing.T) { + // This key was altered so that the self signatures following the + // subkey are in a sub-optimal order. + // + // Note: Should someone have to create a similar key again, look into + // gpgsplit, gpg --dearmor, and gpg --enarmor. + // + // The packet ordering is the following: + // PUBKEY UID UIDSELFSIG SUBKEY SELFSIG1 SELFSIG2 + // + // Where: + // SELFSIG1 expires on 2018-06-14 and was created first + // SELFSIG2 does not expire and was created after SELFSIG1 + // + // Test for RFC 4880 5.2.3.3: + // > An implementation that encounters multiple self-signatures on the + // > same object may resolve the ambiguity in any way it sees fit, but it + // > is RECOMMENDED that priority be given to the most recent self- + // > signature. + // + // This means that we should keep SELFSIG2. + + keys, err := ReadArmoredKeyRing(bytes.NewBufferString(keyWithSubKeyAndBadSelfSigOrder)) + if err != nil { + t.Fatal(err) + } + + if len(keys) != 1 { + t.Fatal("Failed to read key with a sub key and a bad selfsig packet order") + } + + key := keys[0] + + if numKeys, expected := len(key.Subkeys), 1; numKeys != expected { + t.Fatalf("Read %d subkeys, expected %d", numKeys, expected) + } + + subKey := key.Subkeys[0] + + if lifetime := subKey.Sig.KeyLifetimeSecs; lifetime != nil { + t.Errorf("The signature has a key lifetime (%d), but it should be nil", *lifetime) + } + +} + func TestKeyUsage(t *testing.T) { kring, err := ReadKeyRing(readerFromHex(subkeyUsageHex)) if err != nil { @@ -370,100 +480,16 @@ func TestNewEntityWithoutPreferredSymmetric(t *testing.T) { } } -const expiringKeyHex = "988d0451d1ec5d010400ba3385721f2dc3f4ab096b2ee867ab77213f0a27a8538441c35d2fa225b08798a1439a66a5150e6bdc3f40f5d28d588c712394c632b6299f77db8c0d48d37903fb72ebd794d61be6aa774688839e5fdecfe06b2684cc115d240c98c66cb1ef22ae84e3aa0c2b0c28665c1e7d4d044e7f270706193f5223c8d44e0d70b7b8da830011010001b40f4578706972792074657374206b657988be041301020028050251d1ec5d021b03050900278d00060b090807030206150802090a0b0416020301021e01021780000a091072589ad75e237d8c033503fd10506d72837834eb7f994117740723adc39227104b0d326a1161871c0b415d25b4aedef946ca77ea4c05af9c22b32cf98be86ab890111fced1ee3f75e87b7cc3c00dc63bbc85dfab91c0dc2ad9de2c4d13a34659333a85c6acc1a669c5e1d6cecb0cf1e56c10e72d855ae177ddc9e766f9b2dda57ccbb75f57156438bbdb4e42b88d0451d1ec5d0104009c64906559866c5cb61578f5846a94fcee142a489c9b41e67b12bb54cfe86eb9bc8566460f9a720cb00d6526fbccfd4f552071a8e3f7744b1882d01036d811ee5a3fb91a1c568055758f43ba5d2c6a9676b012f3a1a89e47bbf624f1ad571b208f3cc6224eb378f1645dd3d47584463f9eadeacfd1ce6f813064fbfdcc4b5a53001101000188a504180102000f021b0c050251d1f06b050900093e89000a091072589ad75e237d8c20e00400ab8310a41461425b37889c4da28129b5fae6084fafbc0a47dd1adc74a264c6e9c9cc125f40462ee1433072a58384daef88c961c390ed06426a81b464a53194c4e291ddd7e2e2ba3efced01537d713bd111f48437bde2363446200995e8e0d4e528dda377fd1e8f8ede9c8e2198b393bd86852ce7457a7e3daf74d510461a5b77b88d0451d1ece8010400b3a519f83ab0010307e83bca895170acce8964a044190a2b368892f7a244758d9fc193482648acb1fb9780d28cc22d171931f38bb40279389fc9bf2110876d4f3db4fcfb13f22f7083877fe56592b3b65251312c36f83ffcb6d313c6a17f197dd471f0712aad15a8537b435a92471ba2e5b0c72a6c72536c3b567c558d7b6051001101000188a504180102000f021b0c050251d1f07b050900279091000a091072589ad75e237d8ce69e03fe286026afacf7c97ee20673864d4459a2240b5655219950643c7dba0ac384b1d4359c67805b21d98211f7b09c2a0ccf6410c8c04d4ff4a51293725d8d6570d9d8bb0e10c07d22357caeb49626df99c180be02d77d1fe8ed25e7a54481237646083a9f89a11566cd20b9e995b1487c5f9e02aeb434f3a1897cd416dd0a87861838da3e9e" -const subkeyUsageHex = "988d04533a52bc010400d26af43085558f65b9e7dbc90cb9238015259aed5e954637adcfa2181548b2d0b60c65f1f42ec5081cbf1bc0a8aa4900acfb77070837c58f26012fbce297d70afe96e759ad63531f0037538e70dbf8e384569b9720d99d8eb39d8d0a2947233ed242436cb6ac7dfe74123354b3d0119b5c235d3dd9c9d6c004f8ffaf67ad8583001101000188b7041f010200210502533b8552170c8001ce094aa433f7040bb2ddf0be3893cb843d0fe70c020700000a0910a42704b92866382aa98404009d63d916a27543da4221c60087c33f1c44bec9998c5438018ed370cca4962876c748e94b73eb39c58eb698063f3fd6346d58dd2a11c0247934c4a9d71f24754f7468f96fb24c3e791dd2392b62f626148ad724189498cbf993db2df7c0cdc2d677c35da0f16cb16c9ce7c33b4de65a4a91b1d21a130ae9cc26067718910ef8e2b417556d627261203c756d627261407379642e65642e61753e88b80413010200220502533a52bc021b03060b090807030206150802090a0b0416020301021e01021780000a0910a42704b92866382a47840400c0c2bd04f5fca586de408b395b3c280a278259c93eaaa8b79a53b97003f8ed502a8a00446dd9947fb462677e4fcac0dac2f0701847d15130aadb6cd9e0705ea0cf5f92f129136c7be21a718d46c8e641eb7f044f2adae573e11ae423a0a9ca51324f03a8a2f34b91fa40c3cc764bee4dccadedb54c768ba0469b683ea53f1c29b88d04533a52bc01040099c92a5d6f8b744224da27bc2369127c35269b58bec179de6bbc038f749344222f85a31933224f26b70243c4e4b2d242f0c4777eaef7b5502f9dad6d8bf3aaeb471210674b74de2d7078af497d55f5cdad97c7bedfbc1b41e8065a97c9c3d344b21fc81d27723af8e374bc595da26ea242dccb6ae497be26eea57e563ed517e90011010001889f0418010200090502533a52bc021b0c000a0910a42704b92866382afa1403ff70284c2de8a043ff51d8d29772602fa98009b7861c540535f874f2c230af8caf5638151a636b21f8255003997ccd29747fdd06777bb24f9593bd7d98a3e887689bf902f999915fcc94625ae487e5d13e6616f89090ebc4fdc7eb5cad8943e4056995bb61c6af37f8043016876a958ec7ebf39c43d20d53b7f546cfa83e8d2604b88d04533b8283010400c0b529316dbdf58b4c54461e7e669dc11c09eb7f73819f178ccd4177b9182b91d138605fcf1e463262fabefa73f94a52b5e15d1904635541c7ea540f07050ce0fb51b73e6f88644cec86e91107c957a114f69554548a85295d2b70bd0b203992f76eb5d493d86d9eabcaa7ef3fc7db7e458438db3fcdb0ca1cc97c638439a9170011010001889f0418010200090502533b8283021b0c000a0910a42704b92866382adc6d0400cfff6258485a21675adb7a811c3e19ebca18851533f75a7ba317950b9997fda8d1a4c8c76505c08c04b6c2cc31dc704d33da36a21273f2b388a1a706f7c3378b66d887197a525936ed9a69acb57fe7f718133da85ec742001c5d1864e9c6c8ea1b94f1c3759cebfd93b18606066c063a63be86085b7e37bdbc65f9a915bf084bb901a204533b85cd110400aed3d2c52af2b38b5b67904b0ef73d6dd7aef86adb770e2b153cd22489654dcc91730892087bb9856ae2d9f7ed1eb48f214243fe86bfe87b349ebd7c30e630e49c07b21fdabf78b7a95c8b7f969e97e3d33f2e074c63552ba64a2ded7badc05ce0ea2be6d53485f6900c7860c7aa76560376ce963d7271b9b54638a4028b573f00a0d8854bfcdb04986141568046202192263b9b67350400aaa1049dbc7943141ef590a70dcb028d730371d92ea4863de715f7f0f16d168bd3dc266c2450457d46dcbbf0b071547e5fbee7700a820c3750b236335d8d5848adb3c0da010e998908dfd93d961480084f3aea20b247034f8988eccb5546efaa35a92d0451df3aaf1aee5aa36a4c4d462c760ecd9cebcabfbe1412b1f21450f203fd126687cd486496e971a87fd9e1a8a765fe654baa219a6871ab97768596ab05c26c1aeea8f1a2c72395a58dbc12ef9640d2b95784e974a4d2d5a9b17c25fedacfe551bda52602de8f6d2e48443f5dd1a2a2a8e6a5e70ecdb88cd6e766ad9745c7ee91d78cc55c3d06536b49c3fee6c3d0b6ff0fb2bf13a314f57c953b8f4d93bf88e70418010200090502533b85cd021b0200520910a42704b92866382a47200419110200060502533b85cd000a091042ce2c64bc0ba99214b2009e26b26852c8b13b10c35768e40e78fbbb48bd084100a0c79d9ea0844fa5853dd3c85ff3ecae6f2c9dd6c557aa04008bbbc964cd65b9b8299d4ebf31f41cc7264b8cf33a00e82c5af022331fac79efc9563a822497ba012953cefe2629f1242fcdcb911dbb2315985bab060bfd58261ace3c654bdbbe2e8ed27a46e836490145c86dc7bae15c011f7e1ffc33730109b9338cd9f483e7cef3d2f396aab5bd80efb6646d7e778270ee99d934d187dd98" -const revokedKeyHex = "988d045331ce82010400c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be10011010001889f04200102000905025331d0e3021d03000a0910a401d9f09a34f7c042aa040086631196405b7e6af71026b88e98012eab44aa9849f6ef3fa930c7c9f23deaedba9db1538830f8652fb7648ec3fcade8dbcbf9eaf428e83c6cbcc272201bfe2fbb90d41963397a7c0637a1a9d9448ce695d9790db2dc95433ad7be19eb3de72dacf1d6db82c3644c13eae2a3d072b99bb341debba012c5ce4006a7d34a1f4b94b444526567205265766f6b657220283c52656727732022424d204261726973746122204b657920262530305c303e5c29203c72656740626d626172697374612e636f2e61753e88b704130102002205025331ce82021b03060b090807030206150802090a0b0416020301021e01021780000a0910a401d9f09a34f7c0019c03f75edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56889c04100102000605025331cfb5000a0910fe9645554e8266b64b4303fc084075396674fb6f778d302ac07cef6bc0b5d07b66b2004c44aef711cbac79617ef06d836b4957522d8772dd94bf41a2f4ac8b1ee6d70c57503f837445a74765a076d07b829b8111fc2a918423ddb817ead7ca2a613ef0bfb9c6b3562aec6c3cf3c75ef3031d81d95f6563e4cdcc9960bcb386c5d757b104fcca5fe11fc709df884604101102000605025331cfe7000a09107b15a67f0b3ddc0317f6009e360beea58f29c1d963a22b962b80788c3fa6c84e009d148cfde6b351469b8eae91187eff07ad9d08fcaab88d045331ce820104009f25e20a42b904f3fa555530fe5c46737cf7bd076c35a2a0d22b11f7e0b61a69320b768f4a80fe13980ce380d1cfc4a0cd8fbe2d2e2ef85416668b77208baa65bf973fe8e500e78cc310d7c8705cdb34328bf80e24f0385fce5845c33bc7943cf6b11b02348a23da0bf6428e57c05135f2dc6bd7c1ce325d666d5a5fd2fd5e410011010001889f04180102000905025331ce82021b0c000a0910a401d9f09a34f7c0418003fe34feafcbeaef348a800a0d908a7a6809cc7304017d820f70f0474d5e23cb17e38b67dc6dca282c6ca00961f4ec9edf2738d0f087b1d81e4871ef08e1798010863afb4eac4c44a376cb343be929c5be66a78cfd4456ae9ec6a99d97f4e1c3ff3583351db2147a65c0acef5c003fb544ab3a2e2dc4d43646f58b811a6c3a369d1f" -const revokedSubkeyHex = "988d04533121f6010400aefc803a3e4bb1a61c86e8a86d2726c6a43e0079e9f2713f1fa017e9854c83877f4aced8e331d675c67ea83ddab80aacbfa0b9040bb12d96f5a3d6be09455e2a76546cbd21677537db941cab710216b6d24ec277ee0bd65b910f416737ed120f6b93a9d3b306245c8cfd8394606fdb462e5cf43c551438d2864506c63367fc890011010001b41d416c696365203c616c69636540626d626172697374612e636f2e61753e88bb041301020025021b03060b090807030206150802090a0b0416020301021e01021780050253312798021901000a09104ef7e4beccde97f015a803ff5448437780f63263b0df8442a995e7f76c221351a51edd06f2063d8166cf3157aada4923dfc44aa0f2a6a4da5cf83b7fe722ba8ab416c976e77c6b5682e7f1069026673bd0de56ba06fd5d7a9f177607f277d9b55ff940a638c3e68525c67517e2b3d976899b93ca267f705b3e5efad7d61220e96b618a4497eab8d04403d23f8846041011020006050253312910000a09107b15a67f0b3ddc03d96e009f50b6365d86c4be5d5e9d0ea42d5e56f5794c617700a0ab274e19c2827780016d23417ce89e0a2c0d987d889c04100102000605025331cf7a000a0910a401d9f09a34f7c0ee970400aca292f213041c9f3b3fc49148cbda9d84afee6183c8dd6c5ff2600b29482db5fecd4303797be1ee6d544a20a858080fec43412061c9a71fae4039fd58013b4ae341273e6c66ad4c7cdd9e68245bedb260562e7b166f2461a1032f2b38c0e0e5715fb3d1656979e052b55ca827a76f872b78a9fdae64bc298170bfcebedc1271b41a416c696365203c616c696365407379646973702e6f722e61753e88b804130102002205025331278b021b03060b090807030206150802090a0b0416020301021e01021780000a09104ef7e4beccde97f06a7003fa03c3af68d272ebc1fa08aa72a03b02189c26496a2833d90450801c4e42c5b5f51ad96ce2d2c9cef4b7c02a6a2fcf1412d6a2d486098eb762f5010a201819c17fd2888aec8eda20c65a3b75744de7ee5cc8ac7bfc470cbe3cb982720405a27a3c6a8c229cfe36905f881b02ed5680f6a8f05866efb9d6c5844897e631deb949ca8846041011020006050253312910000a09107b15a67f0b3ddc0347bc009f7fa35db59147469eb6f2c5aaf6428accb138b22800a0caa2f5f0874bacc5909c652a57a31beda65eddd5889c04100102000605025331cf7a000a0910a401d9f09a34f7c0316403ff46f2a5c101256627f16384d34a38fb47a6c88ba60506843e532d91614339fccae5f884a5741e7582ffaf292ba38ee10a270a05f139bde3814b6a077e8cd2db0f105ebea2a83af70d385f13b507fac2ad93ff79d84950328bb86f3074745a8b7f9b64990fb142e2a12976e27e8d09a28dc5621f957ac49091116da410ac3cbde1b88d04533121f6010400cbd785b56905e4192e2fb62a720727d43c4fa487821203cf72138b884b78b701093243e1d8c92a0248a6c0203a5a88693da34af357499abacaf4b3309c640797d03093870a323b4b6f37865f6eaa2838148a67df4735d43a90ca87942554cdf1c4a751b1e75f9fd4ce4e97e278d6c1c7ed59d33441df7d084f3f02beb68896c70011010001889f0418010200090502533121f6021b0c000a09104ef7e4beccde97f0b98b03fc0a5ccf6a372995835a2f5da33b282a7d612c0ab2a97f59cf9fff73e9110981aac2858c41399afa29624a7fd8a0add11654e3d882c0fd199e161bdad65e5e2548f7b68a437ea64293db1246e3011cbb94dc1bcdeaf0f2539bd88ff16d95547144d97cead6a8c5927660a91e6db0d16eb36b7b49a3525b54d1644e65599b032b7eb901a204533127a0110400bd3edaa09eff9809c4edc2c2a0ebe52e53c50a19c1e49ab78e6167bf61473bb08f2050d78a5cbbc6ed66aff7b42cd503f16b4a0b99fa1609681fca9b7ce2bbb1a5b3864d6cdda4d7ef7849d156d534dea30fb0efb9e4cf8959a2b2ce623905882d5430b995a15c3b9fe92906086788b891002924f94abe139b42cbbfaaabe42f00a0b65dc1a1ad27d798adbcb5b5ad02d2688c89477b03ff4eebb6f7b15a73b96a96bed201c0e5e4ea27e4c6e2dd1005b94d4b90137a5b1cf5e01c6226c070c4cc999938101578877ee76d296b9aab8246d57049caacf489e80a3f40589cade790a020b1ac146d6f7a6241184b8c7fcde680eae3188f5dcbe846d7f7bdad34f6fcfca08413e19c1d5df83fc7c7c627d493492e009c2f52a80400a2fe82de87136fd2e8845888c4431b032ba29d9a29a804277e31002a8201fb8591a3e55c7a0d0881496caf8b9fb07544a5a4879291d0dc026a0ea9e5bd88eb4aa4947bbd694b25012e208a250d65ddc6f1eea59d3aed3b4ec15fcab85e2afaa23a40ab1ef9ce3e11e1bc1c34a0e758e7aa64deb8739276df0af7d4121f834a9b88e70418010200090502533127a0021b02005209104ef7e4beccde97f047200419110200060502533127a0000a0910dbce4ee19529437fe045009c0b32f5ead48ee8a7e98fac0dea3d3e6c0e2c552500a0ad71fadc5007cfaf842d9b7db3335a8cdad15d3d1a6404009b08e2c68fe8f3b45c1bb72a4b3278cdf3012aa0f229883ad74aa1f6000bb90b18301b2f85372ca5d6b9bf478d235b733b1b197d19ccca48e9daf8e890cb64546b4ce1b178faccfff07003c172a2d4f5ebaba9f57153955f3f61a9b80a4f5cb959908f8b211b03b7026a8a82fc612bfedd3794969bcf458c4ce92be215a1176ab88d045331d144010400a5063000c5aaf34953c1aa3bfc95045b3aab9882b9a8027fecfe2142dc6b47ba8aca667399990244d513dd0504716908c17d92c65e74219e004f7b83fc125e575dd58efec3ab6dd22e3580106998523dea42ec75bf9aa111734c82df54630bebdff20fe981cfc36c76f865eb1c2fb62c9e85bc3a6e5015a361a2eb1c8431578d0011010001889f04280102000905025331d433021d03000a09104ef7e4beccde97f02e5503ff5e0630d1b65291f4882b6d40a29da4616bb5088717d469fbcc3648b8276de04a04988b1f1b9f3e18f52265c1f8b6c85861691c1a6b8a3a25a1809a0b32ad330aec5667cb4262f4450649184e8113849b05e5ad06a316ea80c001e8e71838190339a6e48bbde30647bcf245134b9a97fa875c1d83a9862cae87ffd7e2c4ce3a1b89013d04180102000905025331d144021b0200a809104ef7e4beccde97f09d2004190102000605025331d144000a0910677815e371c2fd23522203fe22ab62b8e7a151383cea3edd3a12995693911426f8ccf125e1f6426388c0010f88d9ca7da2224aee8d1c12135998640c5e1813d55a93df472faae75bef858457248db41b4505827590aeccf6f9eb646da7f980655dd3050c6897feddddaca90676dee856d66db8923477d251712bb9b3186b4d0114daf7d6b59272b53218dd1da94a03ff64006fcbe71211e5daecd9961fba66cdb6de3f914882c58ba5beddeba7dcb950c1156d7fba18c19ea880dccc800eae335deec34e3b84ac75ffa24864f782f87815cda1c0f634b3dd2fa67cea30811d21723d21d9551fa12ccbcfa62b6d3a15d01307b99925707992556d50065505b090aadb8579083a20fe65bd2a270da9b011" -const missingCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- -Charset: UTF-8 +func TestNewEntityPublicSerialization(t *testing.T) { + entity, err := NewEntity("Golang Gopher", "Test Key", "no-reply@golang.com", nil) + if err != nil { + t.Fatal(err) + } + serializedEntity := bytes.NewBuffer(nil) + entity.Serialize(serializedEntity) -mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY -ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG -zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54 -QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ -QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo -9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu -Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/ -dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R -JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL -ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew -RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW -/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu -yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAJcXQeP+NmuciE99YcJoffxv -2gVLU4ZXBNHEaP0mgaJ1+tmMD089vUQAcyGRvw8jfsNsVZQIOAuRxY94aHQhIRHR -bUzBN28ofo/AJJtfx62C15xt6fDKRV6HXYqAiygrHIpEoRLyiN69iScUsjIJeyFL -C8wa72e8pSL6dkHoaV1N9ZH/xmrJ+k0vsgkQaAh9CzYufncDxcwkoP+aOlGtX1gP -WwWoIbz0JwLEMPHBWvDDXQcQPQTYQyj+LGC9U6f9VZHN25E94subM1MjuT9OhN9Y -MLfWaaIc5WyhLFyQKW2Upofn9wSFi8ubyBnv640Dfd0rVmaWv7LNTZpoZ/GbJAMA -EQEAAYkBHwQYAQIACQUCU5ygeQIbAgAKCRDt1A0FCB6SP0zCB/sEzaVR38vpx+OQ -MMynCBJrakiqDmUZv9xtplY7zsHSQjpd6xGflbU2n+iX99Q+nav0ETQZifNUEd4N -1ljDGQejcTyKD6Pkg6wBL3x9/RJye7Zszazm4+toJXZ8xJ3800+BtaPoI39akYJm -+ijzbskvN0v/j5GOFJwQO0pPRAFtdHqRs9Kf4YanxhedB4dIUblzlIJuKsxFit6N -lgGRblagG3Vv2eBszbxzPbJjHCgVLR3RmrVezKOsZjr/2i7X+xLWIR0uD3IN1qOW -CXQxLBizEEmSNVNxsp7KPGTLnqO3bPtqFirxS9PJLIMPTPLNBY7ZYuPNTMqVIUWF -4artDmrG -=7FfJ ------END PGP PUBLIC KEY BLOCK-----` - -const invalidCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY -ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG -zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54 -QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ -QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo -9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu -Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/ -dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R -JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL -ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew -RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW -/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu -yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAIINDqlj7X6jYKc6DjwrOkjQ -UIRWbQQar0LwmNilehmt70g5DCL1SYm9q4LcgJJ2Nhxj0/5qqsYib50OSWMcKeEe -iRXpXzv1ObpcQtI5ithp0gR53YPXBib80t3bUzomQ5UyZqAAHzMp3BKC54/vUrSK -FeRaxDzNLrCeyI00+LHNUtwghAqHvdNcsIf8VRumK8oTm3RmDh0TyjASWYbrt9c8 -R1Um3zuoACOVy+mEIgIzsfHq0u7dwYwJB5+KeM7ZLx+HGIYdUYzHuUE1sLwVoELh -+SHIGHI1HDicOjzqgajShuIjj5hZTyQySVprrsLKiXS6NEwHAP20+XjayJ/R3tEA -EQEAAYkCPgQYAQIBKAUCU5ygeQIbAsBdIAQZAQIABgUCU5ygeQAKCRCpVlnFZmhO -52RJB/9uD1MSa0wjY6tHOIgquZcP3bHBvHmrHNMw9HR2wRCMO91ZkhrpdS3ZHtgb -u3/55etj0FdvDo1tb8P8FGSVtO5Vcwf5APM8sbbqoi8L951Q3i7qt847lfhu6sMl -w0LWFvPTOLHrliZHItPRjOltS1WAWfr2jUYhsU9ytaDAJmvf9DujxEOsN5G1YJep -54JCKVCkM/y585Zcnn+yxk/XwqoNQ0/iJUT9qRrZWvoeasxhl1PQcwihCwss44A+ -YXaAt3hbk+6LEQuZoYS73yR3WHj+42tfm7YxRGeubXfgCEz/brETEWXMh4pe0vCL -bfWrmfSPq2rDegYcAybxRQz0lF8PAAoJEO3UDQUIHpI/exkH/0vQfdHA8g/N4T6E -i6b1CUVBAkvtdJpCATZjWPhXmShOw62gkDw306vHPilL4SCvEEi4KzG72zkp6VsB -DSRcpxCwT4mHue+duiy53/aRMtSJ+vDfiV1Vhq+3sWAck/yUtfDU9/u4eFaiNok1 -8/Gd7reyuZt5CiJnpdPpjCwelK21l2w7sHAnJF55ITXdOxI8oG3BRKufz0z5lyDY -s2tXYmhhQIggdgelN8LbcMhWs/PBbtUr6uZlNJG2lW1yscD4aI529VjwJlCeo745 -U7pO4eF05VViUJ2mmfoivL3tkhoTUWhx8xs8xCUcCg8DoEoSIhxtOmoTPR22Z9BL -6LCg2mg= -=Dhm4 ------END PGP PUBLIC KEY BLOCK-----` - -const goodCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1 - -mI0EVUqeVwEEAMufHRrMPWK3gyvi0O0tABCs/oON9zV9KDZlr1a1M91ShCSFwCPo -7r80PxdWVWcj0V5h50/CJYtpN3eE/mUIgW2z1uDYQF1OzrQ8ubrksfsJvpAhENom -lTQEppv9mV8qhcM278teb7TX0pgrUHLYF5CfPdp1L957JLLXoQR/lwLVABEBAAG0 -E2dvb2Qtc2lnbmluZy1zdWJrZXmIuAQTAQIAIgUCVUqeVwIbAwYLCQgHAwIGFQgC -CQoLBBYCAwECHgECF4AACgkQNRjL95IRWP69XQQAlH6+eyXJN4DZTLX78KGjHrsw -6FCvxxClEPtPUjcJy/1KCRQmtLAt9PbbA78dvgzjDeZMZqRAwdjyJhjyg/fkU2OH -7wq4ktjUu+dLcOBb+BFMEY+YjKZhf6EJuVfxoTVr5f82XNPbYHfTho9/OABKH6kv -X70PaKZhbwnwij8Nts65AaIEVUqftREEAJ3WxZfqAX0bTDbQPf2CMT2IVMGDfhK7 -GyubOZgDFFjwUJQvHNvsrbeGLZ0xOBumLINyPO1amIfTgJNm1iiWFWfmnHReGcDl -y5mpYG60Mb79Whdcer7CMm3AqYh/dW4g6IB02NwZMKoUHo3PXmFLxMKXnWyJ0clw -R0LI/Qn509yXAKDh1SO20rqrBM+EAP2c5bfI98kyNwQAi3buu94qo3RR1ZbvfxgW -CKXDVm6N99jdZGNK7FbRifXqzJJDLcXZKLnstnC4Sd3uyfyf1uFhmDLIQRryn5m+ -LBYHfDBPN3kdm7bsZDDq9GbTHiFZUfm/tChVKXWxkhpAmHhU/tH6GGzNSMXuIWSO -aOz3Rqq0ED4NXyNKjdF9MiwD/i83S0ZBc0LmJYt4Z10jtH2B6tYdqnAK29uQaadx -yZCX2scE09UIm32/w7pV77CKr1Cp/4OzAXS1tmFzQ+bX7DR+Gl8t4wxr57VeEMvl -BGw4Vjh3X8//m3xynxycQU18Q1zJ6PkiMyPw2owZ/nss3hpSRKFJsxMLhW3fKmKr -Ey2KiOcEGAECAAkFAlVKn7UCGwIAUgkQNRjL95IRWP5HIAQZEQIABgUCVUqftQAK -CRD98VjDN10SqkWrAKDTpEY8D8HC02E/KVC5YUI01B30wgCgurpILm20kXEDCeHp -C5pygfXw1DJrhAP+NyPJ4um/bU1I+rXaHHJYroYJs8YSweiNcwiHDQn0Engh/mVZ -SqLHvbKh2dL/RXymC3+rjPvQf5cup9bPxNMa6WagdYBNAfzWGtkVISeaQW+cTEp/ -MtgVijRGXR/lGLGETPg2X3Afwn9N9bLMBkBprKgbBqU7lpaoPupxT61bL70= -=vtbN ------END PGP PUBLIC KEY BLOCK-----` + _, err = ReadEntity(packet.NewReader(bytes.NewBuffer(serializedEntity.Bytes()))) + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go index 266840d0..02b372cf 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go @@ -42,12 +42,18 @@ func (e *EncryptedKey) parse(r io.Reader) (err error) { switch e.Algo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) + if err != nil { + return + } case PubKeyAlgoElGamal: e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r) if err != nil { return } e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r) + if err != nil { + return + } } _, err = consumeAll(r) return @@ -72,7 +78,8 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error { // padding oracle attacks. switch priv.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly: - b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes) + k := priv.PrivateKey.(*rsa.PrivateKey) + b, err = rsa.DecryptPKCS1v15(config.Random(), k, padToKeySize(&k.PublicKey, e.encryptedMPI1.bytes)) case PubKeyAlgoElGamal: c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes) c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes) diff --git a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go index fee14cf3..f2fcf4d3 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go @@ -39,39 +39,44 @@ var encryptedKeyPriv = &PrivateKey{ } func TestDecryptingEncryptedKey(t *testing.T) { - const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8" - const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b" + for i, encryptedKeyHex := range []string{ + "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8", + // MPI can be shorter than the length of the key. + "c18b032a67d68660df41c70103f8e520c52ae9807183c669ce26e772e482dc5d8cf60e6f59316e145be14d2e5221ee69550db1d5618a8cb002a719f1f0b9345bde21536d410ec90ba86cac37748dec7933eb7f9873873b2d61d3321d1cd44535014f6df58f7bc0c7afb5edc38e1a974428997d2f747f9a173bea9ca53079b409517d332df62d805564cffc9be6", + } { + const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b" - p, err := Read(readerFromHex(encryptedKeyHex)) - if err != nil { - t.Errorf("error from Read: %s", err) - return - } - ek, ok := p.(*EncryptedKey) - if !ok { - t.Errorf("didn't parse an EncryptedKey, got %#v", p) - return - } + p, err := Read(readerFromHex(encryptedKeyHex)) + if err != nil { + t.Errorf("#%d: error from Read: %s", i, err) + return + } + ek, ok := p.(*EncryptedKey) + if !ok { + t.Errorf("#%d: didn't parse an EncryptedKey, got %#v", i, p) + return + } - if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA { - t.Errorf("unexpected EncryptedKey contents: %#v", ek) - return - } + if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA { + t.Errorf("#%d: unexpected EncryptedKey contents: %#v", i, ek) + return + } - err = ek.Decrypt(encryptedKeyPriv, nil) - if err != nil { - t.Errorf("error from Decrypt: %s", err) - return - } + err = ek.Decrypt(encryptedKeyPriv, nil) + if err != nil { + t.Errorf("#%d: error from Decrypt: %s", i, err) + return + } - if ek.CipherFunc != CipherAES256 { - t.Errorf("unexpected EncryptedKey contents: %#v", ek) - return - } + if ek.CipherFunc != CipherAES256 { + t.Errorf("#%d: unexpected EncryptedKey contents: %#v", i, ek) + return + } - keyHex := fmt.Sprintf("%x", ek.Key) - if keyHex != expectedKeyHex { - t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex) + keyHex := fmt.Sprintf("%x", ek.Key) + if keyHex != expectedKeyHex { + t.Errorf("#%d: bad key, got %s want %s", i, keyHex, expectedKeyHex) + } } } @@ -121,7 +126,7 @@ func TestEncryptingEncryptedKey(t *testing.T) { keyHex := fmt.Sprintf("%x", ek.Key) if keyHex != expectedKeyHex { - t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex) + t.Errorf("bad key, got %s want %s", keyHex, expectedKeyHex) } } diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go index 3eded93f..5af64c54 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go @@ -11,10 +11,12 @@ import ( "crypto/aes" "crypto/cipher" "crypto/des" - "golang.org/x/crypto/cast5" - "golang.org/x/crypto/openpgp/errors" + "crypto/rsa" "io" "math/big" + + "golang.org/x/crypto/cast5" + "golang.org/x/crypto/openpgp/errors" ) // readFull is the same as io.ReadFull except that reading zero bytes returns @@ -402,14 +404,16 @@ const ( type PublicKeyAlgorithm uint8 const ( - PubKeyAlgoRSA PublicKeyAlgorithm = 1 - PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 - PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 - PubKeyAlgoElGamal PublicKeyAlgorithm = 16 - PubKeyAlgoDSA PublicKeyAlgorithm = 17 + PubKeyAlgoRSA PublicKeyAlgorithm = 1 + PubKeyAlgoElGamal PublicKeyAlgorithm = 16 + PubKeyAlgoDSA PublicKeyAlgorithm = 17 // RFC 6637, Section 5. PubKeyAlgoECDH PublicKeyAlgorithm = 18 PubKeyAlgoECDSA PublicKeyAlgorithm = 19 + + // Deprecated in RFC 4880, Section 13.5. Use key flags instead. + PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2 + PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3 ) // CanEncrypt returns true if it's possible to encrypt a message to a public @@ -500,19 +504,17 @@ func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) { numBytes := (int(bitLength) + 7) / 8 mpi = make([]byte, numBytes) _, err = readFull(r, mpi) - return -} - -// mpiLength returns the length of the given *big.Int when serialized as an -// MPI. -func mpiLength(n *big.Int) (mpiLengthInBytes int) { - mpiLengthInBytes = 2 /* MPI length */ - mpiLengthInBytes += (n.BitLen() + 7) / 8 + // According to RFC 4880 3.2. we should check that the MPI has no leading + // zeroes (at least when not an encrypted MPI?), but this implementation + // does generate leading zeroes, so we keep accepting them. return } // writeMPI serializes a big integer to w. func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) { + // Note that we can produce leading zeroes, in violation of RFC 4880 3.2. + // Implementations seem to be tolerant of them, and stripping them would + // make it complex to guarantee matching re-serialization. _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)}) if err == nil { _, err = w.Write(mpiBytes) @@ -525,6 +527,18 @@ func writeBig(w io.Writer, i *big.Int) error { return writeMPI(w, uint16(i.BitLen()), i.Bytes()) } +// padToKeySize left-pads a MPI with zeroes to match the length of the +// specified RSA public. +func padToKeySize(pub *rsa.PublicKey, b []byte) []byte { + k := (pub.N.BitLen() + 7) / 8 + if len(b) >= k { + return b + } + bb := make([]byte, k) + copy(bb[len(bb)-len(b):], b) + return bb +} + // CompressionAlgo Represents the different compression algorithms // supported by OpenPGP (except for BZIP2, which is not currently // supported). See Section 9.3 of RFC 4880. diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go index 34734cc6..bd31ccea 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go @@ -64,14 +64,19 @@ func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateK return pk } -// NewSignerPrivateKey creates a sign-only PrivateKey from a crypto.Signer that +// NewSignerPrivateKey creates a PrivateKey from a crypto.Signer that // implements RSA or ECDSA. func NewSignerPrivateKey(currentTime time.Time, signer crypto.Signer) *PrivateKey { pk := new(PrivateKey) + // In general, the public Keys should be used as pointers. We still + // type-switch on the values, for backwards-compatibility. switch pubkey := signer.Public().(type) { + case *rsa.PublicKey: + pk.PublicKey = *NewRSAPublicKey(currentTime, pubkey) case rsa.PublicKey: pk.PublicKey = *NewRSAPublicKey(currentTime, &pubkey) - pk.PubKeyAlgo = PubKeyAlgoRSASignOnly + case *ecdsa.PublicKey: + pk.PublicKey = *NewECDSAPublicKey(currentTime, pubkey) case ecdsa.PublicKey: pk.PublicKey = *NewECDSAPublicKey(currentTime, &pubkey) default: diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go index ac651d91..cc08b483 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go @@ -14,7 +14,6 @@ import ( "crypto/x509" "encoding/hex" "hash" - "io" "testing" "time" ) @@ -162,15 +161,7 @@ func TestECDSAPrivateKey(t *testing.T) { } type rsaSigner struct { - priv *rsa.PrivateKey -} - -func (s *rsaSigner) Public() crypto.PublicKey { - return s.priv.PublicKey -} - -func (s *rsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { - return s.priv.Sign(rand, msg, opts) + *rsa.PrivateKey } func TestRSASignerPrivateKey(t *testing.T) { @@ -181,12 +172,8 @@ func TestRSASignerPrivateKey(t *testing.T) { priv := NewSignerPrivateKey(time.Now(), &rsaSigner{rsaPriv}) - if priv.PubKeyAlgo != PubKeyAlgoRSASignOnly { - t.Fatal("NewSignerPrivateKey should have made a sign-only RSA private key") - } - sig := &Signature{ - PubKeyAlgo: PubKeyAlgoRSASignOnly, + PubKeyAlgo: PubKeyAlgoRSA, Hash: crypto.SHA256, } msg := []byte("Hello World!") @@ -208,15 +195,7 @@ func TestRSASignerPrivateKey(t *testing.T) { } type ecdsaSigner struct { - priv *ecdsa.PrivateKey -} - -func (s *ecdsaSigner) Public() crypto.PublicKey { - return s.priv.PublicKey -} - -func (s *ecdsaSigner) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) { - return s.priv.Sign(rand, msg, opts) + *ecdsa.PrivateKey } func TestECDSASignerPrivateKey(t *testing.T) { diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go index ead26233..fcd5f525 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go @@ -244,7 +244,12 @@ func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey } pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) - pk.ec.p.bitLength = uint16(8 * len(pk.ec.p.bytes)) + + // The bit length is 3 (for the 0x04 specifying an uncompressed key) + // plus two field elements (for x and y), which are rounded up to the + // nearest byte. See https://tools.ietf.org/html/rfc6637#section-6 + fieldBytes := (pub.Curve.Params().BitSize + 7) & ^7 + pk.ec.p.bitLength = uint16(3 + fieldBytes + fieldBytes) pk.setFingerPrintAndKeyId() return pk @@ -515,7 +520,7 @@ func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err erro switch pk.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey) - err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes) + err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)) if err != nil { return errors.SignatureError("RSA verification failure") } @@ -566,7 +571,7 @@ func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err switch pk.PubKeyAlgo { case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly: rsaPublicKey := pk.PublicKey.(*rsa.PublicKey) - if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil { + if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, padToKeySize(rsaPublicKey, sig.RSASignature.bytes)); err != nil { return errors.SignatureError("RSA verification failure") } return diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go index 7ad7d918..103696ee 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go @@ -6,7 +6,10 @@ package packet import ( "bytes" + "crypto/ecdsa" + "crypto/elliptic" "encoding/hex" + "math/big" "testing" "time" ) @@ -186,6 +189,29 @@ func TestEcc384Serialize(t *testing.T) { } } +func TestP256KeyID(t *testing.T) { + // Confirm that key IDs are correctly calculated for ECC keys. + ecdsaPub := &ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: fromHex("81fbbc20eea9e8d1c3ceabb0a8185925b113d1ac42cd5c78403bd83da19235c6"), + Y: fromHex("5ed6db13d91db34507d0129bf88981878d29adbf8fcd1720afdb767bb3fcaaff"), + } + pub := NewECDSAPublicKey(time.Unix(1297309478, 0), ecdsaPub) + + const want = uint64(0xd01055fbcadd268e) + if pub.KeyId != want { + t.Errorf("want key ID: %x, got %x", want, pub.KeyId) + } +} + +func fromHex(hex string) *big.Int { + n, ok := new(big.Int).SetString(hex, 16) + if !ok { + panic("bad hex number: " + hex) + } + return n +} + const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb" const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001" diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature.go b/vendor/golang.org/x/crypto/openpgp/packet/signature.go index 6ce0cbed..b2a24a53 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/signature.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/signature.go @@ -542,7 +542,7 @@ func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err e r, s, err = ecdsa.Sign(config.Random(), pk, digest) } else { var b []byte - b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, nil) + b, err = priv.PrivateKey.(crypto.Signer).Sign(config.Random(), digest, sig.Hash) if err == nil { r, s, err = unwrapECDSASig(b) } diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go index 96a2b382..d19ffbc7 100644 --- a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go +++ b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go @@ -80,7 +80,7 @@ func (uat *UserAttribute) Serialize(w io.Writer) (err error) { // ImageData returns zero or more byte slices, each containing // JPEG File Interchange Format (JFIF), for each photo in the -// the user attribute packet. +// user attribute packet. func (uat *UserAttribute) ImageData() (imageData [][]byte) { for _, sp := range uat.Contents { if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 { diff --git a/vendor/golang.org/x/crypto/openpgp/read_test.go b/vendor/golang.org/x/crypto/openpgp/read_test.go index 1fbfbac4..f5bba301 100644 --- a/vendor/golang.org/x/crypto/openpgp/read_test.go +++ b/vendor/golang.org/x/crypto/openpgp/read_test.go @@ -124,7 +124,7 @@ func checkSignedMessage(t *testing.T, signedHex, expected string) { return } - if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.IsSymmetricallyEncrypted { + if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.DecryptedWith != (Key{}) { t.Errorf("bad MessageDetails: %#v", md) } diff --git a/vendor/golang.org/x/crypto/openpgp/write.go b/vendor/golang.org/x/crypto/openpgp/write.go index 65a304cc..4ee71784 100644 --- a/vendor/golang.org/x/crypto/openpgp/write.go +++ b/vendor/golang.org/x/crypto/openpgp/write.go @@ -164,12 +164,12 @@ func hashToHashId(h crypto.Hash) uint8 { return v } -// Encrypt encrypts a message to a number of recipients and, optionally, signs -// it. hints contains optional information, that is also encrypted, that aids -// the recipients in processing the message. The resulting WriteCloser must -// be closed after the contents of the file have been written. -// If config is nil, sensible defaults will be used. -func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { +// writeAndSign writes the data as a payload package and, optionally, signs +// it. hints contains optional information, that is also encrypted, +// that aids the recipients in processing the message. The resulting +// WriteCloser must be closed after the contents of the file have been +// written. If config is nil, sensible defaults will be used. +func writeAndSign(payload io.WriteCloser, candidateHashes []uint8, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { var signer *packet.PrivateKey if signed != nil { signKey, ok := signed.signingKey(config.Now()) @@ -185,6 +185,83 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint } } + var hash crypto.Hash + for _, hashId := range candidateHashes { + if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { + hash = h + break + } + } + + // If the hash specified by config is a candidate, we'll use that. + if configuredHash := config.Hash(); configuredHash.Available() { + for _, hashId := range candidateHashes { + if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { + hash = h + break + } + } + } + + if hash == 0 { + hashId := candidateHashes[0] + name, ok := s2k.HashIdToString(hashId) + if !ok { + name = "#" + strconv.Itoa(int(hashId)) + } + return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") + } + + if signer != nil { + ops := &packet.OnePassSignature{ + SigType: packet.SigTypeBinary, + Hash: hash, + PubKeyAlgo: signer.PubKeyAlgo, + KeyId: signer.KeyId, + IsLast: true, + } + if err := ops.Serialize(payload); err != nil { + return nil, err + } + } + + if hints == nil { + hints = &FileHints{} + } + + w := payload + if signer != nil { + // If we need to write a signature packet after the literal + // data then we need to stop literalData from closing + // encryptedData. + w = noOpCloser{w} + + } + var epochSeconds uint32 + if !hints.ModTime.IsZero() { + epochSeconds = uint32(hints.ModTime.Unix()) + } + literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) + if err != nil { + return nil, err + } + + if signer != nil { + return signatureWriter{payload, literalData, hash, hash.New(), signer, config}, nil + } + return literalData, nil +} + +// Encrypt encrypts a message to a number of recipients and, optionally, signs +// it. hints contains optional information, that is also encrypted, that aids +// the recipients in processing the message. The resulting WriteCloser must +// be closed after the contents of the file have been written. +// If config is nil, sensible defaults will be used. +func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) { + if len(to) == 0 { + return nil, errors.InvalidArgumentError("no encryption recipient provided") + } + // These are the possible ciphers that we'll use for the message. candidateCiphers := []uint8{ uint8(packet.CipherAES128), @@ -194,6 +271,7 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint // These are the possible hash functions that we'll use for the signature. candidateHashes := []uint8{ hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA384), hashToHashId(crypto.SHA512), hashToHashId(crypto.SHA1), hashToHashId(crypto.RIPEMD160), @@ -241,33 +319,6 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint } } - var hash crypto.Hash - for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() { - hash = h - break - } - } - - // If the hash specified by config is a candidate, we'll use that. - if configuredHash := config.Hash(); configuredHash.Available() { - for _, hashId := range candidateHashes { - if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash { - hash = h - break - } - } - } - - if hash == 0 { - hashId := candidateHashes[0] - name, ok := s2k.HashIdToString(hashId) - if !ok { - name = "#" + strconv.Itoa(int(hashId)) - } - return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)") - } - symKey := make([]byte, cipher.KeySize()) if _, err := io.ReadFull(config.Random(), symKey); err != nil { return nil, err @@ -279,49 +330,38 @@ func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHint } } - encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) + payload, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config) if err != nil { return } - if signer != nil { - ops := &packet.OnePassSignature{ - SigType: packet.SigTypeBinary, - Hash: hash, - PubKeyAlgo: signer.PubKeyAlgo, - KeyId: signer.KeyId, - IsLast: true, - } - if err := ops.Serialize(encryptedData); err != nil { - return nil, err - } + return writeAndSign(payload, candidateHashes, signed, hints, config) +} + +// Sign signs a message. The resulting WriteCloser must be closed after the +// contents of the file have been written. hints contains optional information +// that aids the recipients in processing the message. +// If config is nil, sensible defaults will be used. +func Sign(output io.Writer, signed *Entity, hints *FileHints, config *packet.Config) (input io.WriteCloser, err error) { + if signed == nil { + return nil, errors.InvalidArgumentError("no signer provided") } - if hints == nil { - hints = &FileHints{} + // These are the possible hash functions that we'll use for the signature. + candidateHashes := []uint8{ + hashToHashId(crypto.SHA256), + hashToHashId(crypto.SHA384), + hashToHashId(crypto.SHA512), + hashToHashId(crypto.SHA1), + hashToHashId(crypto.RIPEMD160), } - - w := encryptedData - if signer != nil { - // If we need to write a signature packet after the literal - // data then we need to stop literalData from closing - // encryptedData. - w = noOpCloser{encryptedData} - + defaultHashes := candidateHashes[len(candidateHashes)-1:] + preferredHashes := signed.primaryIdentity().SelfSignature.PreferredHash + if len(preferredHashes) == 0 { + preferredHashes = defaultHashes } - var epochSeconds uint32 - if !hints.ModTime.IsZero() { - epochSeconds = uint32(hints.ModTime.Unix()) - } - literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds) - if err != nil { - return nil, err - } - - if signer != nil { - return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil - } - return literalData, nil + candidateHashes = intersectPreferences(candidateHashes, preferredHashes) + return writeAndSign(noOpCloser{output}, candidateHashes, signed, hints, config) } // signatureWriter hashes the contents of a message while passing it along to diff --git a/vendor/golang.org/x/crypto/openpgp/write_test.go b/vendor/golang.org/x/crypto/openpgp/write_test.go index f2d50a0c..cbc8f4da 100644 --- a/vendor/golang.org/x/crypto/openpgp/write_test.go +++ b/vendor/golang.org/x/crypto/openpgp/write_test.go @@ -271,3 +271,92 @@ func TestEncryption(t *testing.T) { } } } + +var testSigningTests = []struct { + keyRingHex string +}{ + { + testKeys1And2PrivateHex, + }, + { + dsaElGamalTestKeysHex, + }, +} + +func TestSigning(t *testing.T) { + for i, test := range testSigningTests { + kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex)) + + passphrase := []byte("passphrase") + for _, entity := range kring { + if entity.PrivateKey != nil && entity.PrivateKey.Encrypted { + err := entity.PrivateKey.Decrypt(passphrase) + if err != nil { + t.Errorf("#%d: failed to decrypt key", i) + } + } + for _, subkey := range entity.Subkeys { + if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted { + err := subkey.PrivateKey.Decrypt(passphrase) + if err != nil { + t.Errorf("#%d: failed to decrypt subkey", i) + } + } + } + } + + signed := kring[0] + + buf := new(bytes.Buffer) + w, err := Sign(buf, signed, nil /* no hints */, nil) + if err != nil { + t.Errorf("#%d: error in Sign: %s", i, err) + continue + } + + const message = "testing" + _, err = w.Write([]byte(message)) + if err != nil { + t.Errorf("#%d: error writing plaintext: %s", i, err) + continue + } + err = w.Close() + if err != nil { + t.Errorf("#%d: error closing WriteCloser: %s", i, err) + continue + } + + md, err := ReadMessage(buf, kring, nil /* no prompt */, nil) + if err != nil { + t.Errorf("#%d: error reading message: %s", i, err) + continue + } + + testTime, _ := time.Parse("2006-01-02", "2013-07-01") + signKey, _ := kring[0].signingKey(testTime) + expectedKeyId := signKey.PublicKey.KeyId + if md.SignedByKeyId != expectedKeyId { + t.Errorf("#%d: message signed by wrong key id, got: %v, want: %v", i, *md.SignedBy, expectedKeyId) + } + if md.SignedBy == nil { + t.Errorf("#%d: failed to find the signing Entity", i) + } + + plaintext, err := ioutil.ReadAll(md.UnverifiedBody) + if err != nil { + t.Errorf("#%d: error reading contents: %v", i, err) + continue + } + + if string(plaintext) != message { + t.Errorf("#%d: got: %q, want: %q", i, plaintext, message) + } + + if md.SignatureError != nil { + t.Errorf("#%d: signature error: %q", i, md.SignatureError) + } + if md.Signature == nil { + t.Error("signature missing") + } + } +} diff --git a/vendor/golang.org/x/crypto/poly1305/poly1305_test.go b/vendor/golang.org/x/crypto/poly1305/poly1305_test.go index 017027fe..256bdbba 100644 --- a/vendor/golang.org/x/crypto/poly1305/poly1305_test.go +++ b/vendor/golang.org/x/crypto/poly1305/poly1305_test.go @@ -5,7 +5,6 @@ package poly1305 import ( - "bytes" "encoding/hex" "flag" "testing" @@ -14,80 +13,51 @@ import ( var stressFlag = flag.Bool("stress", false, "run slow stress tests") -var testData = []struct { - in, k, correct []byte -}{ - { - []byte("Hello world!"), - []byte("this is 32-byte key for Poly1305"), - []byte{0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0}, - }, - { - make([]byte, 32), - []byte("this is 32-byte key for Poly1305"), - []byte{0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07}, - }, - { - make([]byte, 2007), - []byte("this is 32-byte key for Poly1305"), - []byte{0xda, 0x84, 0xbc, 0xab, 0x02, 0x67, 0x6c, 0x38, 0xcd, 0xb0, 0x15, 0x60, 0x42, 0x74, 0xc2, 0xaa}, - }, - { - make([]byte, 2007), - make([]byte, 32), - make([]byte, 16), - }, - { - // This test triggers an edge-case. See https://go-review.googlesource.com/#/c/30101/. - []byte{0x81, 0xd8, 0xb2, 0xe4, 0x6a, 0x25, 0x21, 0x3b, 0x58, 0xfe, 0xe4, 0x21, 0x3a, 0x2a, 0x28, 0xe9, 0x21, 0xc1, 0x2a, 0x96, 0x32, 0x51, 0x6d, 0x3b, 0x73, 0x27, 0x27, 0x27, 0xbe, 0xcf, 0x21, 0x29}, - []byte{0x3b, 0x3a, 0x29, 0xe9, 0x3b, 0x21, 0x3a, 0x5c, 0x5c, 0x3b, 0x3b, 0x05, 0x3a, 0x3a, 0x8c, 0x0d}, - []byte{0x6d, 0xc1, 0x8b, 0x8c, 0x34, 0x4c, 0xd7, 0x99, 0x27, 0x11, 0x8b, 0xbe, 0x84, 0xb7, 0xf3, 0x14}, - }, - { - // This test generates a result of (2^130-1) % (2^130-5). - []byte{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - []byte{4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, - { - // This test generates a result of (2^130-6) % (2^130-5). - []byte{ - 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - []byte{0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, - }, - { - // This test generates a result of (2^130-5) % (2^130-5). - []byte{ - 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - }, +type test struct { + in string + key string + tag string } -func testSum(t *testing.T, unaligned bool) { - var out [16]byte - var key [32]byte +func (t *test) Input() []byte { + in, err := hex.DecodeString(t.in) + if err != nil { + panic(err) + } + return in +} +func (t *test) Key() [32]byte { + buf, err := hex.DecodeString(t.key) + if err != nil { + panic(err) + } + var key [32]byte + copy(key[:], buf[:32]) + return key +} + +func (t *test) Tag() [16]byte { + buf, err := hex.DecodeString(t.tag) + if err != nil { + panic(err) + } + var tag [16]byte + copy(tag[:], buf[:16]) + return tag +} + +func testSum(t *testing.T, unaligned bool, sumImpl func(tag *[TagSize]byte, msg []byte, key *[32]byte)) { + var tag [16]byte for i, v := range testData { - in := v.in + in := v.Input() if unaligned { in = unalignBytes(in) } - copy(key[:], v.k) - Sum(&out, in, &key) - if !bytes.Equal(out[:], v.correct) { - t.Errorf("%d: expected %x, got %x", i, v.correct, out[:]) + key := v.Key() + sumImpl(&tag, in, &key) + if tag != v.Tag() { + t.Errorf("%d: expected %x, got %x", i, v.Tag(), tag[:]) } } } @@ -125,8 +95,10 @@ func TestBurnin(t *testing.T) { } } -func TestSum(t *testing.T) { testSum(t, false) } -func TestSumUnaligned(t *testing.T) { testSum(t, true) } +func TestSum(t *testing.T) { testSum(t, false, Sum) } +func TestSumUnaligned(t *testing.T) { testSum(t, true, Sum) } +func TestSumGeneric(t *testing.T) { testSum(t, false, sumGeneric) } +func TestSumGenericUnaligned(t *testing.T) { testSum(t, true, sumGeneric) } func benchmark(b *testing.B, size int, unaligned bool) { var out [16]byte @@ -146,6 +118,7 @@ func Benchmark64(b *testing.B) { benchmark(b, 64, false) } func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) } func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) } func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) } +func Benchmark2M(b *testing.B) { benchmark(b, 2097152, true) } func unalignBytes(in []byte) []byte { out := make([]byte, len(in)+1) diff --git a/vendor/golang.org/x/crypto/poly1305/sum_noasm.go b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go new file mode 100644 index 00000000..751eec52 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_noasm.go @@ -0,0 +1,14 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,!go1.11 !arm,!amd64,!s390x gccgo appengine nacl + +package poly1305 + +// Sum generates an authenticator for msg using a one-time key and puts the +// 16-byte result into out. Authenticating two different messages with the same +// key allows an attacker to forge messages at will. +func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { + sumGeneric(out, msg, key) +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ref.go b/vendor/golang.org/x/crypto/poly1305/sum_ref.go index b2805a5c..c4d59bd0 100644 --- a/vendor/golang.org/x/crypto/poly1305/sum_ref.go +++ b/vendor/golang.org/x/crypto/poly1305/sum_ref.go @@ -2,16 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!arm gccgo appengine nacl - package poly1305 import "encoding/binary" -// Sum generates an authenticator for msg using a one-time key and puts the -// 16-byte result into out. Authenticating two different messages with the same -// key allows an attacker to forge messages at will. -func Sum(out *[TagSize]byte, msg []byte, key *[32]byte) { +// sumGeneric generates an authenticator for msg using a one-time key and +// puts the 16-byte result into out. This is the generic implementation of +// Sum and should be called if no assembly implementation is available. +func sumGeneric(out *[TagSize]byte, msg []byte, key *[32]byte) { var ( h0, h1, h2, h3, h4 uint32 // the hash accumulators r0, r1, r2, r3, r4 uint64 // the r part of the key diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.go b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go new file mode 100644 index 00000000..7a266cec --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.go @@ -0,0 +1,49 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,go1.11,!gccgo,!appengine + +package poly1305 + +// hasVectorFacility reports whether the machine supports +// the vector facility (vx). +func hasVectorFacility() bool + +// hasVMSLFacility reports whether the machine supports +// Vector Multiply Sum Logical (VMSL). +func hasVMSLFacility() bool + +var hasVX = hasVectorFacility() +var hasVMSL = hasVMSLFacility() + +// poly1305vx is an assembly implementation of Poly1305 that uses vector +// instructions. It must only be called if the vector facility (vx) is +// available. +//go:noescape +func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]byte) + +// poly1305vmsl is an assembly implementation of Poly1305 that uses vector +// instructions, including VMSL. It must only be called if the vector facility (vx) is +// available and if VMSL is supported. +//go:noescape +func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]byte) + +// Sum generates an authenticator for m using a one-time key and puts the +// 16-byte result into out. Authenticating two different messages with the same +// key allows an attacker to forge messages at will. +func Sum(out *[16]byte, m []byte, key *[32]byte) { + if hasVX { + var mPtr *byte + if len(m) > 0 { + mPtr = &m[0] + } + if hasVMSL && len(m) > 256 { + poly1305vmsl(out, mPtr, uint64(len(m)), key) + } else { + poly1305vx(out, mPtr, uint64(len(m)), key) + } + } else { + sumGeneric(out, m, key) + } +} diff --git a/vendor/golang.org/x/crypto/poly1305/sum_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s new file mode 100644 index 00000000..356c07a6 --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_s390x.s @@ -0,0 +1,400 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,go1.11,!gccgo,!appengine + +#include "textflag.h" + +// Implementation of Poly1305 using the vector facility (vx). + +// constants +#define MOD26 V0 +#define EX0 V1 +#define EX1 V2 +#define EX2 V3 + +// temporaries +#define T_0 V4 +#define T_1 V5 +#define T_2 V6 +#define T_3 V7 +#define T_4 V8 + +// key (r) +#define R_0 V9 +#define R_1 V10 +#define R_2 V11 +#define R_3 V12 +#define R_4 V13 +#define R5_1 V14 +#define R5_2 V15 +#define R5_3 V16 +#define R5_4 V17 +#define RSAVE_0 R5 +#define RSAVE_1 R6 +#define RSAVE_2 R7 +#define RSAVE_3 R8 +#define RSAVE_4 R9 +#define R5SAVE_1 V28 +#define R5SAVE_2 V29 +#define R5SAVE_3 V30 +#define R5SAVE_4 V31 + +// message block +#define F_0 V18 +#define F_1 V19 +#define F_2 V20 +#define F_3 V21 +#define F_4 V22 + +// accumulator +#define H_0 V23 +#define H_1 V24 +#define H_2 V25 +#define H_3 V26 +#define H_4 V27 + +GLOBL ·keyMask<>(SB), RODATA, $16 +DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f +DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f + +GLOBL ·bswapMask<>(SB), RODATA, $16 +DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908 +DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100 + +GLOBL ·constants<>(SB), RODATA, $64 +// MOD26 +DATA ·constants<>+0(SB)/8, $0x3ffffff +DATA ·constants<>+8(SB)/8, $0x3ffffff +// EX0 +DATA ·constants<>+16(SB)/8, $0x0006050403020100 +DATA ·constants<>+24(SB)/8, $0x1016151413121110 +// EX1 +DATA ·constants<>+32(SB)/8, $0x060c0b0a09080706 +DATA ·constants<>+40(SB)/8, $0x161c1b1a19181716 +// EX2 +DATA ·constants<>+48(SB)/8, $0x0d0d0d0d0d0f0e0d +DATA ·constants<>+56(SB)/8, $0x1d1d1d1d1d1f1e1d + +// h = (f*g) % (2**130-5) [partial reduction] +#define MULTIPLY(f0, f1, f2, f3, f4, g0, g1, g2, g3, g4, g51, g52, g53, g54, h0, h1, h2, h3, h4) \ + VMLOF f0, g0, h0 \ + VMLOF f0, g1, h1 \ + VMLOF f0, g2, h2 \ + VMLOF f0, g3, h3 \ + VMLOF f0, g4, h4 \ + VMLOF f1, g54, T_0 \ + VMLOF f1, g0, T_1 \ + VMLOF f1, g1, T_2 \ + VMLOF f1, g2, T_3 \ + VMLOF f1, g3, T_4 \ + VMALOF f2, g53, h0, h0 \ + VMALOF f2, g54, h1, h1 \ + VMALOF f2, g0, h2, h2 \ + VMALOF f2, g1, h3, h3 \ + VMALOF f2, g2, h4, h4 \ + VMALOF f3, g52, T_0, T_0 \ + VMALOF f3, g53, T_1, T_1 \ + VMALOF f3, g54, T_2, T_2 \ + VMALOF f3, g0, T_3, T_3 \ + VMALOF f3, g1, T_4, T_4 \ + VMALOF f4, g51, h0, h0 \ + VMALOF f4, g52, h1, h1 \ + VMALOF f4, g53, h2, h2 \ + VMALOF f4, g54, h3, h3 \ + VMALOF f4, g0, h4, h4 \ + VAG T_0, h0, h0 \ + VAG T_1, h1, h1 \ + VAG T_2, h2, h2 \ + VAG T_3, h3, h3 \ + VAG T_4, h4, h4 + +// carry h0->h1 h3->h4, h1->h2 h4->h0, h0->h1 h2->h3, h3->h4 +#define REDUCE(h0, h1, h2, h3, h4) \ + VESRLG $26, h0, T_0 \ + VESRLG $26, h3, T_1 \ + VN MOD26, h0, h0 \ + VN MOD26, h3, h3 \ + VAG T_0, h1, h1 \ + VAG T_1, h4, h4 \ + VESRLG $26, h1, T_2 \ + VESRLG $26, h4, T_3 \ + VN MOD26, h1, h1 \ + VN MOD26, h4, h4 \ + VESLG $2, T_3, T_4 \ + VAG T_3, T_4, T_4 \ + VAG T_2, h2, h2 \ + VAG T_4, h0, h0 \ + VESRLG $26, h2, T_0 \ + VESRLG $26, h0, T_1 \ + VN MOD26, h2, h2 \ + VN MOD26, h0, h0 \ + VAG T_0, h3, h3 \ + VAG T_1, h1, h1 \ + VESRLG $26, h3, T_2 \ + VN MOD26, h3, h3 \ + VAG T_2, h4, h4 + +// expand in0 into d[0] and in1 into d[1] +#define EXPAND(in0, in1, d0, d1, d2, d3, d4) \ + VGBM $0x0707, d1 \ // d1=tmp + VPERM in0, in1, EX2, d4 \ + VPERM in0, in1, EX0, d0 \ + VPERM in0, in1, EX1, d2 \ + VN d1, d4, d4 \ + VESRLG $26, d0, d1 \ + VESRLG $30, d2, d3 \ + VESRLG $4, d2, d2 \ + VN MOD26, d0, d0 \ + VN MOD26, d1, d1 \ + VN MOD26, d2, d2 \ + VN MOD26, d3, d3 + +// pack h4:h0 into h1:h0 (no carry) +#define PACK(h0, h1, h2, h3, h4) \ + VESLG $26, h1, h1 \ + VESLG $26, h3, h3 \ + VO h0, h1, h0 \ + VO h2, h3, h2 \ + VESLG $4, h2, h2 \ + VLEIB $7, $48, h1 \ + VSLB h1, h2, h2 \ + VO h0, h2, h0 \ + VLEIB $7, $104, h1 \ + VSLB h1, h4, h3 \ + VO h3, h0, h0 \ + VLEIB $7, $24, h1 \ + VSRLB h1, h4, h1 + +// if h > 2**130-5 then h -= 2**130-5 +#define MOD(h0, h1, t0, t1, t2) \ + VZERO t0 \ + VLEIG $1, $5, t0 \ + VACCQ h0, t0, t1 \ + VAQ h0, t0, t0 \ + VONE t2 \ + VLEIG $1, $-4, t2 \ + VAQ t2, t1, t1 \ + VACCQ h1, t1, t1 \ + VONE t2 \ + VAQ t2, t1, t1 \ + VN h0, t1, t2 \ + VNC t0, t1, t1 \ + VO t1, t2, h0 + +// func poly1305vx(out *[16]byte, m *byte, mlen uint64, key *[32]key) +TEXT ·poly1305vx(SB), $0-32 + // This code processes up to 2 blocks (32 bytes) per iteration + // using the algorithm described in: + // NEON crypto, Daniel J. Bernstein & Peter Schwabe + // https://cryptojedi.org/papers/neoncrypto-20120320.pdf + LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key + + // load MOD26, EX0, EX1 and EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), MOD26, EX2 + + // setup r + VL (R4), T_0 + MOVD $·keyMask<>(SB), R6 + VL (R6), T_1 + VN T_0, T_1, T_0 + EXPAND(T_0, T_0, R_0, R_1, R_2, R_3, R_4) + + // setup r*5 + VLEIG $0, $5, T_0 + VLEIG $1, $5, T_0 + + // store r (for final block) + VMLOF T_0, R_1, R5SAVE_1 + VMLOF T_0, R_2, R5SAVE_2 + VMLOF T_0, R_3, R5SAVE_3 + VMLOF T_0, R_4, R5SAVE_4 + VLGVG $0, R_0, RSAVE_0 + VLGVG $0, R_1, RSAVE_1 + VLGVG $0, R_2, RSAVE_2 + VLGVG $0, R_3, RSAVE_3 + VLGVG $0, R_4, RSAVE_4 + + // skip r**2 calculation + CMPBLE R3, $16, skip + + // calculate r**2 + MULTIPLY(R_0, R_1, R_2, R_3, R_4, R_0, R_1, R_2, R_3, R_4, R5SAVE_1, R5SAVE_2, R5SAVE_3, R5SAVE_4, H_0, H_1, H_2, H_3, H_4) + REDUCE(H_0, H_1, H_2, H_3, H_4) + VLEIG $0, $5, T_0 + VLEIG $1, $5, T_0 + VMLOF T_0, H_1, R5_1 + VMLOF T_0, H_2, R5_2 + VMLOF T_0, H_3, R5_3 + VMLOF T_0, H_4, R5_4 + VLR H_0, R_0 + VLR H_1, R_1 + VLR H_2, R_2 + VLR H_3, R_3 + VLR H_4, R_4 + + // initialize h + VZERO H_0 + VZERO H_1 + VZERO H_2 + VZERO H_3 + VZERO H_4 + +loop: + CMPBLE R3, $32, b2 + VLM (R2), T_0, T_1 + SUB $32, R3 + MOVD $32(R2), R2 + EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) + VLEIB $4, $1, F_4 + VLEIB $12, $1, F_4 + +multiply: + VAG H_0, F_0, F_0 + VAG H_1, F_1, F_1 + VAG H_2, F_2, F_2 + VAG H_3, F_3, F_3 + VAG H_4, F_4, F_4 + MULTIPLY(F_0, F_1, F_2, F_3, F_4, R_0, R_1, R_2, R_3, R_4, R5_1, R5_2, R5_3, R5_4, H_0, H_1, H_2, H_3, H_4) + REDUCE(H_0, H_1, H_2, H_3, H_4) + CMPBNE R3, $0, loop + +finish: + // sum vectors + VZERO T_0 + VSUMQG H_0, T_0, H_0 + VSUMQG H_1, T_0, H_1 + VSUMQG H_2, T_0, H_2 + VSUMQG H_3, T_0, H_3 + VSUMQG H_4, T_0, H_4 + + // h may be >= 2*(2**130-5) so we need to reduce it again + REDUCE(H_0, H_1, H_2, H_3, H_4) + + // carry h1->h4 + VESRLG $26, H_1, T_1 + VN MOD26, H_1, H_1 + VAQ T_1, H_2, H_2 + VESRLG $26, H_2, T_2 + VN MOD26, H_2, H_2 + VAQ T_2, H_3, H_3 + VESRLG $26, H_3, T_3 + VN MOD26, H_3, H_3 + VAQ T_3, H_4, H_4 + + // h is now < 2*(2**130-5) + // pack h into h1 (hi) and h0 (lo) + PACK(H_0, H_1, H_2, H_3, H_4) + + // if h > 2**130-5 then h -= 2**130-5 + MOD(H_0, H_1, T_0, T_1, T_2) + + // h += s + MOVD $·bswapMask<>(SB), R5 + VL (R5), T_1 + VL 16(R4), T_0 + VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big) + VAQ T_0, H_0, H_0 + VPERM H_0, H_0, T_1, H_0 // reverse bytes (to little) + VST H_0, (R1) + + RET + +b2: + CMPBLE R3, $16, b1 + + // 2 blocks remaining + SUB $17, R3 + VL (R2), T_0 + VLL R3, 16(R2), T_1 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, T_1 + EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) + CMPBNE R3, $16, 2(PC) + VLEIB $12, $1, F_4 + VLEIB $4, $1, F_4 + + // setup [r²,r] + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, RSAVE_3, R_3 + VLVGG $1, RSAVE_4, R_4 + VPDI $0, R5_1, R5SAVE_1, R5_1 + VPDI $0, R5_2, R5SAVE_2, R5_2 + VPDI $0, R5_3, R5SAVE_3, R5_3 + VPDI $0, R5_4, R5SAVE_4, R5_4 + + MOVD $0, R3 + BR multiply + +skip: + VZERO H_0 + VZERO H_1 + VZERO H_2 + VZERO H_3 + VZERO H_4 + + CMPBEQ R3, $0, finish + +b1: + // 1 block remaining + SUB $1, R3 + VLL R3, (R2), T_0 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, T_0 + VZERO T_1 + EXPAND(T_0, T_1, F_0, F_1, F_2, F_3, F_4) + CMPBNE R3, $16, 2(PC) + VLEIB $4, $1, F_4 + VLEIG $1, $1, R_0 + VZERO R_1 + VZERO R_2 + VZERO R_3 + VZERO R_4 + VZERO R5_1 + VZERO R5_2 + VZERO R5_3 + VZERO R5_4 + + // setup [r, 1] + VLVGG $0, RSAVE_0, R_0 + VLVGG $0, RSAVE_1, R_1 + VLVGG $0, RSAVE_2, R_2 + VLVGG $0, RSAVE_3, R_3 + VLVGG $0, RSAVE_4, R_4 + VPDI $0, R5SAVE_1, R5_1, R5_1 + VPDI $0, R5SAVE_2, R5_2, R5_2 + VPDI $0, R5SAVE_3, R5_3, R5_3 + VPDI $0, R5SAVE_4, R5_4, R5_4 + + MOVD $0, R3 + BR multiply + +TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1 + MOVD $x-24(SP), R1 + XC $24, 0(R1), 0(R1) // clear the storage + MOVD $2, R0 // R0 is the number of double words stored -1 + WORD $0xB2B01000 // STFLE 0(R1) + XOR R0, R0 // reset the value of R0 + MOVBZ z-8(SP), R1 + AND $0x40, R1 + BEQ novector + +vectorinstalled: + // check if the vector instruction has been enabled + VLEIB $0, $0xF, V16 + VLGVB $0, V16, R1 + CMPBNE R1, $0xF, novector + MOVB $1, ret+0(FP) // have vx + RET + +novector: + MOVB $0, ret+0(FP) // no vx + RET diff --git a/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s b/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s new file mode 100644 index 00000000..e548020b --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/sum_vmsl_s390x.s @@ -0,0 +1,931 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build s390x,go1.11,!gccgo,!appengine + +#include "textflag.h" + +// Implementation of Poly1305 using the vector facility (vx) and the VMSL instruction. + +// constants +#define EX0 V1 +#define EX1 V2 +#define EX2 V3 + +// temporaries +#define T_0 V4 +#define T_1 V5 +#define T_2 V6 +#define T_3 V7 +#define T_4 V8 +#define T_5 V9 +#define T_6 V10 +#define T_7 V11 +#define T_8 V12 +#define T_9 V13 +#define T_10 V14 + +// r**2 & r**4 +#define R_0 V15 +#define R_1 V16 +#define R_2 V17 +#define R5_1 V18 +#define R5_2 V19 +// key (r) +#define RSAVE_0 R7 +#define RSAVE_1 R8 +#define RSAVE_2 R9 +#define R5SAVE_1 R10 +#define R5SAVE_2 R11 + +// message block +#define M0 V20 +#define M1 V21 +#define M2 V22 +#define M3 V23 +#define M4 V24 +#define M5 V25 + +// accumulator +#define H0_0 V26 +#define H1_0 V27 +#define H2_0 V28 +#define H0_1 V29 +#define H1_1 V30 +#define H2_1 V31 + +GLOBL ·keyMask<>(SB), RODATA, $16 +DATA ·keyMask<>+0(SB)/8, $0xffffff0ffcffff0f +DATA ·keyMask<>+8(SB)/8, $0xfcffff0ffcffff0f + +GLOBL ·bswapMask<>(SB), RODATA, $16 +DATA ·bswapMask<>+0(SB)/8, $0x0f0e0d0c0b0a0908 +DATA ·bswapMask<>+8(SB)/8, $0x0706050403020100 + +GLOBL ·constants<>(SB), RODATA, $48 +// EX0 +DATA ·constants<>+0(SB)/8, $0x18191a1b1c1d1e1f +DATA ·constants<>+8(SB)/8, $0x0000050403020100 +// EX1 +DATA ·constants<>+16(SB)/8, $0x18191a1b1c1d1e1f +DATA ·constants<>+24(SB)/8, $0x00000a0908070605 +// EX2 +DATA ·constants<>+32(SB)/8, $0x18191a1b1c1d1e1f +DATA ·constants<>+40(SB)/8, $0x0000000f0e0d0c0b + +GLOBL ·c<>(SB), RODATA, $48 +// EX0 +DATA ·c<>+0(SB)/8, $0x0000050403020100 +DATA ·c<>+8(SB)/8, $0x0000151413121110 +// EX1 +DATA ·c<>+16(SB)/8, $0x00000a0908070605 +DATA ·c<>+24(SB)/8, $0x00001a1918171615 +// EX2 +DATA ·c<>+32(SB)/8, $0x0000000f0e0d0c0b +DATA ·c<>+40(SB)/8, $0x0000001f1e1d1c1b + +GLOBL ·reduce<>(SB), RODATA, $32 +// 44 bit +DATA ·reduce<>+0(SB)/8, $0x0 +DATA ·reduce<>+8(SB)/8, $0xfffffffffff +// 42 bit +DATA ·reduce<>+16(SB)/8, $0x0 +DATA ·reduce<>+24(SB)/8, $0x3ffffffffff + +// h = (f*g) % (2**130-5) [partial reduction] +// uses T_0...T_9 temporary registers +// input: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2 +// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9 +// output: m02_0, m02_1, m02_2, m13_0, m13_1, m13_2 +#define MULTIPLY(m02_0, m02_1, m02_2, m13_0, m13_1, m13_2, r_0, r_1, r_2, r5_1, r5_2, m4_0, m4_1, m4_2, m5_0, m5_1, m5_2, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) \ + \ // Eliminate the dependency for the last 2 VMSLs + VMSLG m02_0, r_2, m4_2, m4_2 \ + VMSLG m13_0, r_2, m5_2, m5_2 \ // 8 VMSLs pipelined + VMSLG m02_0, r_0, m4_0, m4_0 \ + VMSLG m02_1, r5_2, V0, T_0 \ + VMSLG m02_0, r_1, m4_1, m4_1 \ + VMSLG m02_1, r_0, V0, T_1 \ + VMSLG m02_1, r_1, V0, T_2 \ + VMSLG m02_2, r5_1, V0, T_3 \ + VMSLG m02_2, r5_2, V0, T_4 \ + VMSLG m13_0, r_0, m5_0, m5_0 \ + VMSLG m13_1, r5_2, V0, T_5 \ + VMSLG m13_0, r_1, m5_1, m5_1 \ + VMSLG m13_1, r_0, V0, T_6 \ + VMSLG m13_1, r_1, V0, T_7 \ + VMSLG m13_2, r5_1, V0, T_8 \ + VMSLG m13_2, r5_2, V0, T_9 \ + VMSLG m02_2, r_0, m4_2, m4_2 \ + VMSLG m13_2, r_0, m5_2, m5_2 \ + VAQ m4_0, T_0, m02_0 \ + VAQ m4_1, T_1, m02_1 \ + VAQ m5_0, T_5, m13_0 \ + VAQ m5_1, T_6, m13_1 \ + VAQ m02_0, T_3, m02_0 \ + VAQ m02_1, T_4, m02_1 \ + VAQ m13_0, T_8, m13_0 \ + VAQ m13_1, T_9, m13_1 \ + VAQ m4_2, T_2, m02_2 \ + VAQ m5_2, T_7, m13_2 \ + +// SQUARE uses three limbs of r and r_2*5 to output square of r +// uses T_1, T_5 and T_7 temporary registers +// input: r_0, r_1, r_2, r5_2 +// temp: TEMP0, TEMP1, TEMP2 +// output: p0, p1, p2 +#define SQUARE(r_0, r_1, r_2, r5_2, p0, p1, p2, TEMP0, TEMP1, TEMP2) \ + VMSLG r_0, r_0, p0, p0 \ + VMSLG r_1, r5_2, V0, TEMP0 \ + VMSLG r_2, r5_2, p1, p1 \ + VMSLG r_0, r_1, V0, TEMP1 \ + VMSLG r_1, r_1, p2, p2 \ + VMSLG r_0, r_2, V0, TEMP2 \ + VAQ TEMP0, p0, p0 \ + VAQ TEMP1, p1, p1 \ + VAQ TEMP2, p2, p2 \ + VAQ TEMP0, p0, p0 \ + VAQ TEMP1, p1, p1 \ + VAQ TEMP2, p2, p2 \ + +// carry h0->h1->h2->h0 || h3->h4->h5->h3 +// uses T_2, T_4, T_5, T_7, T_8, T_9 +// t6, t7, t8, t9, t10, t11 +// input: h0, h1, h2, h3, h4, h5 +// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11 +// output: h0, h1, h2, h3, h4, h5 +#define REDUCE(h0, h1, h2, h3, h4, h5, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) \ + VLM (R12), t6, t7 \ // 44 and 42 bit clear mask + VLEIB $7, $0x28, t10 \ // 5 byte shift mask + VREPIB $4, t8 \ // 4 bit shift mask + VREPIB $2, t11 \ // 2 bit shift mask + VSRLB t10, h0, t0 \ // h0 byte shift + VSRLB t10, h1, t1 \ // h1 byte shift + VSRLB t10, h2, t2 \ // h2 byte shift + VSRLB t10, h3, t3 \ // h3 byte shift + VSRLB t10, h4, t4 \ // h4 byte shift + VSRLB t10, h5, t5 \ // h5 byte shift + VSRL t8, t0, t0 \ // h0 bit shift + VSRL t8, t1, t1 \ // h2 bit shift + VSRL t11, t2, t2 \ // h2 bit shift + VSRL t8, t3, t3 \ // h3 bit shift + VSRL t8, t4, t4 \ // h4 bit shift + VESLG $2, t2, t9 \ // h2 carry x5 + VSRL t11, t5, t5 \ // h5 bit shift + VN t6, h0, h0 \ // h0 clear carry + VAQ t2, t9, t2 \ // h2 carry x5 + VESLG $2, t5, t9 \ // h5 carry x5 + VN t6, h1, h1 \ // h1 clear carry + VN t7, h2, h2 \ // h2 clear carry + VAQ t5, t9, t5 \ // h5 carry x5 + VN t6, h3, h3 \ // h3 clear carry + VN t6, h4, h4 \ // h4 clear carry + VN t7, h5, h5 \ // h5 clear carry + VAQ t0, h1, h1 \ // h0->h1 + VAQ t3, h4, h4 \ // h3->h4 + VAQ t1, h2, h2 \ // h1->h2 + VAQ t4, h5, h5 \ // h4->h5 + VAQ t2, h0, h0 \ // h2->h0 + VAQ t5, h3, h3 \ // h5->h3 + VREPG $1, t6, t6 \ // 44 and 42 bit masks across both halves + VREPG $1, t7, t7 \ + VSLDB $8, h0, h0, h0 \ // set up [h0/1/2, h3/4/5] + VSLDB $8, h1, h1, h1 \ + VSLDB $8, h2, h2, h2 \ + VO h0, h3, h3 \ + VO h1, h4, h4 \ + VO h2, h5, h5 \ + VESRLG $44, h3, t0 \ // 44 bit shift right + VESRLG $44, h4, t1 \ + VESRLG $42, h5, t2 \ + VN t6, h3, h3 \ // clear carry bits + VN t6, h4, h4 \ + VN t7, h5, h5 \ + VESLG $2, t2, t9 \ // multiply carry by 5 + VAQ t9, t2, t2 \ + VAQ t0, h4, h4 \ + VAQ t1, h5, h5 \ + VAQ t2, h3, h3 \ + +// carry h0->h1->h2->h0 +// input: h0, h1, h2 +// temp: t0, t1, t2, t3, t4, t5, t6, t7, t8 +// output: h0, h1, h2 +#define REDUCE2(h0, h1, h2, t0, t1, t2, t3, t4, t5, t6, t7, t8) \ + VLEIB $7, $0x28, t3 \ // 5 byte shift mask + VREPIB $4, t4 \ // 4 bit shift mask + VREPIB $2, t7 \ // 2 bit shift mask + VGBM $0x003F, t5 \ // mask to clear carry bits + VSRLB t3, h0, t0 \ + VSRLB t3, h1, t1 \ + VSRLB t3, h2, t2 \ + VESRLG $4, t5, t5 \ // 44 bit clear mask + VSRL t4, t0, t0 \ + VSRL t4, t1, t1 \ + VSRL t7, t2, t2 \ + VESRLG $2, t5, t6 \ // 42 bit clear mask + VESLG $2, t2, t8 \ + VAQ t8, t2, t2 \ + VN t5, h0, h0 \ + VN t5, h1, h1 \ + VN t6, h2, h2 \ + VAQ t0, h1, h1 \ + VAQ t1, h2, h2 \ + VAQ t2, h0, h0 \ + VSRLB t3, h0, t0 \ + VSRLB t3, h1, t1 \ + VSRLB t3, h2, t2 \ + VSRL t4, t0, t0 \ + VSRL t4, t1, t1 \ + VSRL t7, t2, t2 \ + VN t5, h0, h0 \ + VN t5, h1, h1 \ + VESLG $2, t2, t8 \ + VN t6, h2, h2 \ + VAQ t0, h1, h1 \ + VAQ t8, t2, t2 \ + VAQ t1, h2, h2 \ + VAQ t2, h0, h0 \ + +// expands two message blocks into the lower halfs of the d registers +// moves the contents of the d registers into upper halfs +// input: in1, in2, d0, d1, d2, d3, d4, d5 +// temp: TEMP0, TEMP1, TEMP2, TEMP3 +// output: d0, d1, d2, d3, d4, d5 +#define EXPACC(in1, in2, d0, d1, d2, d3, d4, d5, TEMP0, TEMP1, TEMP2, TEMP3) \ + VGBM $0xff3f, TEMP0 \ + VGBM $0xff1f, TEMP1 \ + VESLG $4, d1, TEMP2 \ + VESLG $4, d4, TEMP3 \ + VESRLG $4, TEMP0, TEMP0 \ + VPERM in1, d0, EX0, d0 \ + VPERM in2, d3, EX0, d3 \ + VPERM in1, d2, EX2, d2 \ + VPERM in2, d5, EX2, d5 \ + VPERM in1, TEMP2, EX1, d1 \ + VPERM in2, TEMP3, EX1, d4 \ + VN TEMP0, d0, d0 \ + VN TEMP0, d3, d3 \ + VESRLG $4, d1, d1 \ + VESRLG $4, d4, d4 \ + VN TEMP1, d2, d2 \ + VN TEMP1, d5, d5 \ + VN TEMP0, d1, d1 \ + VN TEMP0, d4, d4 \ + +// expands one message block into the lower halfs of the d registers +// moves the contents of the d registers into upper halfs +// input: in, d0, d1, d2 +// temp: TEMP0, TEMP1, TEMP2 +// output: d0, d1, d2 +#define EXPACC2(in, d0, d1, d2, TEMP0, TEMP1, TEMP2) \ + VGBM $0xff3f, TEMP0 \ + VESLG $4, d1, TEMP2 \ + VGBM $0xff1f, TEMP1 \ + VPERM in, d0, EX0, d0 \ + VESRLG $4, TEMP0, TEMP0 \ + VPERM in, d2, EX2, d2 \ + VPERM in, TEMP2, EX1, d1 \ + VN TEMP0, d0, d0 \ + VN TEMP1, d2, d2 \ + VESRLG $4, d1, d1 \ + VN TEMP0, d1, d1 \ + +// pack h2:h0 into h1:h0 (no carry) +// input: h0, h1, h2 +// output: h0, h1, h2 +#define PACK(h0, h1, h2) \ + VMRLG h1, h2, h2 \ // copy h1 to upper half h2 + VESLG $44, h1, h1 \ // shift limb 1 44 bits, leaving 20 + VO h0, h1, h0 \ // combine h0 with 20 bits from limb 1 + VESRLG $20, h2, h1 \ // put top 24 bits of limb 1 into h1 + VLEIG $1, $0, h1 \ // clear h2 stuff from lower half of h1 + VO h0, h1, h0 \ // h0 now has 88 bits (limb 0 and 1) + VLEIG $0, $0, h2 \ // clear upper half of h2 + VESRLG $40, h2, h1 \ // h1 now has upper two bits of result + VLEIB $7, $88, h1 \ // for byte shift (11 bytes) + VSLB h1, h2, h2 \ // shift h2 11 bytes to the left + VO h0, h2, h0 \ // combine h0 with 20 bits from limb 1 + VLEIG $0, $0, h1 \ // clear upper half of h1 + +// if h > 2**130-5 then h -= 2**130-5 +// input: h0, h1 +// temp: t0, t1, t2 +// output: h0 +#define MOD(h0, h1, t0, t1, t2) \ + VZERO t0 \ + VLEIG $1, $5, t0 \ + VACCQ h0, t0, t1 \ + VAQ h0, t0, t0 \ + VONE t2 \ + VLEIG $1, $-4, t2 \ + VAQ t2, t1, t1 \ + VACCQ h1, t1, t1 \ + VONE t2 \ + VAQ t2, t1, t1 \ + VN h0, t1, t2 \ + VNC t0, t1, t1 \ + VO t1, t2, h0 \ + +// func poly1305vmsl(out *[16]byte, m *byte, mlen uint64, key *[32]key) +TEXT ·poly1305vmsl(SB), $0-32 + // This code processes 6 + up to 4 blocks (32 bytes) per iteration + // using the algorithm described in: + // NEON crypto, Daniel J. Bernstein & Peter Schwabe + // https://cryptojedi.org/papers/neoncrypto-20120320.pdf + // And as moddified for VMSL as described in + // Accelerating Poly1305 Cryptographic Message Authentication on the z14 + // O'Farrell et al, CASCON 2017, p48-55 + // https://ibm.ent.box.com/s/jf9gedj0e9d2vjctfyh186shaztavnht + + LMG out+0(FP), R1, R4 // R1=out, R2=m, R3=mlen, R4=key + VZERO V0 // c + + // load EX0, EX1 and EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), EX0, EX2 // c + + // setup r + VL (R4), T_0 + MOVD $·keyMask<>(SB), R6 + VL (R6), T_1 + VN T_0, T_1, T_0 + VZERO T_2 // limbs for r + VZERO T_3 + VZERO T_4 + EXPACC2(T_0, T_2, T_3, T_4, T_1, T_5, T_7) + + // T_2, T_3, T_4: [0, r] + + // setup r*20 + VLEIG $0, $0, T_0 + VLEIG $1, $20, T_0 // T_0: [0, 20] + VZERO T_5 + VZERO T_6 + VMSLG T_0, T_3, T_5, T_5 + VMSLG T_0, T_4, T_6, T_6 + + // store r for final block in GR + VLGVG $1, T_2, RSAVE_0 // c + VLGVG $1, T_3, RSAVE_1 // c + VLGVG $1, T_4, RSAVE_2 // c + VLGVG $1, T_5, R5SAVE_1 // c + VLGVG $1, T_6, R5SAVE_2 // c + + // initialize h + VZERO H0_0 + VZERO H1_0 + VZERO H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + // initialize pointer for reduce constants + MOVD $·reduce<>(SB), R12 + + // calculate r**2 and 20*(r**2) + VZERO R_0 + VZERO R_1 + VZERO R_2 + SQUARE(T_2, T_3, T_4, T_6, R_0, R_1, R_2, T_1, T_5, T_7) + REDUCE2(R_0, R_1, R_2, M0, M1, M2, M3, M4, R5_1, R5_2, M5, T_1) + VZERO R5_1 + VZERO R5_2 + VMSLG T_0, R_1, R5_1, R5_1 + VMSLG T_0, R_2, R5_2, R5_2 + + // skip r**4 calculation if 3 blocks or less + CMPBLE R3, $48, b4 + + // calculate r**4 and 20*(r**4) + VZERO T_8 + VZERO T_9 + VZERO T_10 + SQUARE(R_0, R_1, R_2, R5_2, T_8, T_9, T_10, T_1, T_5, T_7) + REDUCE2(T_8, T_9, T_10, M0, M1, M2, M3, M4, T_2, T_3, M5, T_1) + VZERO T_2 + VZERO T_3 + VMSLG T_0, T_9, T_2, T_2 + VMSLG T_0, T_10, T_3, T_3 + + // put r**2 to the right and r**4 to the left of R_0, R_1, R_2 + VSLDB $8, T_8, T_8, T_8 + VSLDB $8, T_9, T_9, T_9 + VSLDB $8, T_10, T_10, T_10 + VSLDB $8, T_2, T_2, T_2 + VSLDB $8, T_3, T_3, T_3 + + VO T_8, R_0, R_0 + VO T_9, R_1, R_1 + VO T_10, R_2, R_2 + VO T_2, R5_1, R5_1 + VO T_3, R5_2, R5_2 + + CMPBLE R3, $80, load // less than or equal to 5 blocks in message + + // 6(or 5+1) blocks + SUB $81, R3 + VLM (R2), M0, M4 + VLL R3, 80(R2), M5 + ADD $1, R3 + MOVBZ $1, R0 + CMPBGE R3, $16, 2(PC) + VLVGB R3, R0, M5 + MOVD $96(R2), R2 + EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) + EXPACC(M2, M3, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) + VLEIB $2, $1, H2_0 + VLEIB $2, $1, H2_1 + VLEIB $10, $1, H2_0 + VLEIB $10, $1, H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO T_4 + VZERO T_10 + EXPACC(M4, M5, M0, M1, M2, M3, T_4, T_10, T_0, T_1, T_2, T_3) + VLR T_4, M4 + VLEIB $10, $1, M2 + CMPBLT R3, $16, 2(PC) + VLEIB $10, $1, T_10 + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + + SUB $16, R3 + CMPBLE R3, $0, square + +load: + // load EX0, EX1 and EX2 + MOVD $·c<>(SB), R5 + VLM (R5), EX0, EX2 + +loop: + CMPBLE R3, $64, add // b4 // last 4 or less blocks left + + // next 4 full blocks + VLM (R2), M2, M5 + SUB $64, R3 + MOVD $64(R2), R2 + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, T_0, T_1, T_3, T_4, T_5, T_2, T_7, T_8, T_9) + + // expacc in-lined to create [m2, m3] limbs + VGBM $0x3f3f, T_0 // 44 bit clear mask + VGBM $0x1f1f, T_1 // 40 bit clear mask + VPERM M2, M3, EX0, T_3 + VESRLG $4, T_0, T_0 // 44 bit clear mask ready + VPERM M2, M3, EX1, T_4 + VPERM M2, M3, EX2, T_5 + VN T_0, T_3, T_3 + VESRLG $4, T_4, T_4 + VN T_1, T_5, T_5 + VN T_0, T_4, T_4 + VMRHG H0_1, T_3, H0_0 + VMRHG H1_1, T_4, H1_0 + VMRHG H2_1, T_5, H2_0 + VMRLG H0_1, T_3, H0_1 + VMRLG H1_1, T_4, H1_1 + VMRLG H2_1, T_5, H2_1 + VLEIB $10, $1, H2_0 + VLEIB $10, $1, H2_1 + VPERM M4, M5, EX0, T_3 + VPERM M4, M5, EX1, T_4 + VPERM M4, M5, EX2, T_5 + VN T_0, T_3, T_3 + VESRLG $4, T_4, T_4 + VN T_1, T_5, T_5 + VN T_0, T_4, T_4 + VMRHG V0, T_3, M0 + VMRHG V0, T_4, M1 + VMRHG V0, T_5, M2 + VMRLG V0, T_3, M3 + VMRLG V0, T_4, M4 + VMRLG V0, T_5, M5 + VLEIB $10, $1, M2 + VLEIB $10, $1, M5 + + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + CMPBNE R3, $0, loop + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + + // load EX0, EX1, EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), EX0, EX2 + + // sum vectors + VAQ H0_0, H0_1, H0_0 + VAQ H1_0, H1_1, H1_0 + VAQ H2_0, H2_1, H2_0 + + // h may be >= 2*(2**130-5) so we need to reduce it again + // M0...M4 are used as temps here + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) + +next: // carry h1->h2 + VLEIB $7, $0x28, T_1 + VREPIB $4, T_2 + VGBM $0x003F, T_3 + VESRLG $4, T_3 + + // byte shift + VSRLB T_1, H1_0, T_4 + + // bit shift + VSRL T_2, T_4, T_4 + + // clear h1 carry bits + VN T_3, H1_0, H1_0 + + // add carry + VAQ T_4, H2_0, H2_0 + + // h is now < 2*(2**130-5) + // pack h into h1 (hi) and h0 (lo) + PACK(H0_0, H1_0, H2_0) + + // if h > 2**130-5 then h -= 2**130-5 + MOD(H0_0, H1_0, T_0, T_1, T_2) + + // h += s + MOVD $·bswapMask<>(SB), R5 + VL (R5), T_1 + VL 16(R4), T_0 + VPERM T_0, T_0, T_1, T_0 // reverse bytes (to big) + VAQ T_0, H0_0, H0_0 + VPERM H0_0, H0_0, T_1, H0_0 // reverse bytes (to little) + VST H0_0, (R1) + RET + +add: + // load EX0, EX1, EX2 + MOVD $·constants<>(SB), R5 + VLM (R5), EX0, EX2 + + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + CMPBLE R3, $64, b4 + +b4: + CMPBLE R3, $48, b3 // 3 blocks or less + + // 4(3+1) blocks remaining + SUB $49, R3 + VLM (R2), M0, M2 + VLL R3, 48(R2), M3 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, M3 + MOVD $64(R2), R2 + EXPACC(M0, M1, H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_0, T_1, T_2, T_3) + VLEIB $10, $1, H2_0 + VLEIB $10, $1, H2_1 + VZERO M0 + VZERO M1 + VZERO M4 + VZERO M5 + VZERO T_4 + VZERO T_10 + EXPACC(M2, M3, M0, M1, M4, M5, T_4, T_10, T_0, T_1, T_2, T_3) + VLR T_4, M2 + VLEIB $10, $1, M4 + CMPBNE R3, $16, 2(PC) + VLEIB $10, $1, T_10 + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M4, M5, M2, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M3, M4, M5, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + SUB $16, R3 + CMPBLE R3, $0, square // this condition must always hold true! + +b3: + CMPBLE R3, $32, b2 + + // 3 blocks remaining + + // setup [r²,r] + VSLDB $8, R_0, R_0, R_0 + VSLDB $8, R_1, R_1, R_1 + VSLDB $8, R_2, R_2, R_2 + VSLDB $8, R5_1, R5_1, R5_1 + VSLDB $8, R5_2, R5_2, R5_2 + + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, R5SAVE_1, R5_1 + VLVGG $1, R5SAVE_2, R5_2 + + // setup [h0, h1] + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + VO H0_1, H0_0, H0_0 + VO H1_1, H1_0, H1_0 + VO H2_1, H2_0, H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + + // H*[r**2, r] + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, T_10, M5) + + SUB $33, R3 + VLM (R2), M0, M1 + VLL R3, 32(R2), M2 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, M2 + + // H += m0 + VZERO T_1 + VZERO T_2 + VZERO T_3 + EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6) + VLEIB $10, $1, T_3 + VAG H0_0, T_1, H0_0 + VAG H1_0, T_2, H1_0 + VAG H2_0, T_3, H2_0 + + VZERO M0 + VZERO M3 + VZERO M4 + VZERO M5 + VZERO T_10 + + // (H+m0)*r + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M3, M4, M5, V0, T_10, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_10, H0_1, H1_1, H2_1, T_9) + + // H += m1 + VZERO V0 + VZERO T_1 + VZERO T_2 + VZERO T_3 + EXPACC2(M1, T_1, T_2, T_3, T_4, T_5, T_6) + VLEIB $10, $1, T_3 + VAQ H0_0, T_1, H0_0 + VAQ H1_0, T_2, H1_0 + VAQ H2_0, T_3, H2_0 + REDUCE2(H0_0, H1_0, H2_0, M0, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10) + + // [H, m2] * [r**2, r] + EXPACC2(M2, H0_0, H1_0, H2_0, T_1, T_2, T_3) + CMPBNE R3, $16, 2(PC) + VLEIB $10, $1, H2_0 + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, H0_1, H1_1, M5, T_10) + SUB $16, R3 + CMPBLE R3, $0, next // this condition must always hold true! + +b2: + CMPBLE R3, $16, b1 + + // 2 blocks remaining + + // setup [r²,r] + VSLDB $8, R_0, R_0, R_0 + VSLDB $8, R_1, R_1, R_1 + VSLDB $8, R_2, R_2, R_2 + VSLDB $8, R5_1, R5_1, R5_1 + VSLDB $8, R5_2, R5_2, R5_2 + + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, R5SAVE_1, R5_1 + VLVGG $1, R5SAVE_2, R5_2 + + // setup [h0, h1] + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + VO H0_1, H0_0, H0_0 + VO H1_1, H1_0, H1_0 + VO H2_1, H2_0, H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + + // H*[r**2, r] + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, T_10, M0, M1, M2, M3, M4, T_4, T_5, T_2, T_7, T_8, T_9) + VMRHG V0, H0_1, H0_0 + VMRHG V0, H1_1, H1_0 + VMRHG V0, H2_1, H2_0 + VMRLG V0, H0_1, H0_1 + VMRLG V0, H1_1, H1_1 + VMRLG V0, H2_1, H2_1 + + // move h to the left and 0s at the right + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + + // get message blocks and append 1 to start + SUB $17, R3 + VL (R2), M0 + VLL R3, 16(R2), M1 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, M1 + VZERO T_6 + VZERO T_7 + VZERO T_8 + EXPACC2(M0, T_6, T_7, T_8, T_1, T_2, T_3) + EXPACC2(M1, T_6, T_7, T_8, T_1, T_2, T_3) + VLEIB $2, $1, T_8 + CMPBNE R3, $16, 2(PC) + VLEIB $10, $1, T_8 + + // add [m0, m1] to h + VAG H0_0, T_6, H0_0 + VAG H1_0, T_7, H1_0 + VAG H2_0, T_8, H2_0 + + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + VZERO T_10 + VZERO M0 + + // at this point R_0 .. R5_2 look like [r**2, r] + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M2, M3, M4, M5, T_10, M0, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M2, M3, M4, M5, T_9, H0_1, H1_1, H2_1, T_10) + SUB $16, R3, R3 + CMPBLE R3, $0, next + +b1: + CMPBLE R3, $0, next + + // 1 block remaining + + // setup [r²,r] + VSLDB $8, R_0, R_0, R_0 + VSLDB $8, R_1, R_1, R_1 + VSLDB $8, R_2, R_2, R_2 + VSLDB $8, R5_1, R5_1, R5_1 + VSLDB $8, R5_2, R5_2, R5_2 + + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, R5SAVE_1, R5_1 + VLVGG $1, R5SAVE_2, R5_2 + + // setup [h0, h1] + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + VO H0_1, H0_0, H0_0 + VO H1_1, H1_0, H1_0 + VO H2_1, H2_0, H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + + // H*[r**2, r] + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) + + // set up [0, m0] limbs + SUB $1, R3 + VLL R3, (R2), M0 + ADD $1, R3 + MOVBZ $1, R0 + CMPBEQ R3, $16, 2(PC) + VLVGB R3, R0, M0 + VZERO T_1 + VZERO T_2 + VZERO T_3 + EXPACC2(M0, T_1, T_2, T_3, T_4, T_5, T_6)// limbs: [0, m] + CMPBNE R3, $16, 2(PC) + VLEIB $10, $1, T_3 + + // h+m0 + VAQ H0_0, T_1, H0_0 + VAQ H1_0, T_2, H1_0 + VAQ H2_0, T_3, H2_0 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) + + BR next + +square: + // setup [r²,r] + VSLDB $8, R_0, R_0, R_0 + VSLDB $8, R_1, R_1, R_1 + VSLDB $8, R_2, R_2, R_2 + VSLDB $8, R5_1, R5_1, R5_1 + VSLDB $8, R5_2, R5_2, R5_2 + + VLVGG $1, RSAVE_0, R_0 + VLVGG $1, RSAVE_1, R_1 + VLVGG $1, RSAVE_2, R_2 + VLVGG $1, R5SAVE_1, R5_1 + VLVGG $1, R5SAVE_2, R5_2 + + // setup [h0, h1] + VSLDB $8, H0_0, H0_0, H0_0 + VSLDB $8, H1_0, H1_0, H1_0 + VSLDB $8, H2_0, H2_0, H2_0 + VO H0_1, H0_0, H0_0 + VO H1_1, H1_0, H1_0 + VO H2_1, H2_0, H2_0 + VZERO H0_1 + VZERO H1_1 + VZERO H2_1 + + VZERO M0 + VZERO M1 + VZERO M2 + VZERO M3 + VZERO M4 + VZERO M5 + + // (h0*r**2) + (h1*r) + MULTIPLY(H0_0, H1_0, H2_0, H0_1, H1_1, H2_1, R_0, R_1, R_2, R5_1, R5_2, M0, M1, M2, M3, M4, M5, T_0, T_1, T_2, T_3, T_4, T_5, T_6, T_7, T_8, T_9) + REDUCE2(H0_0, H1_0, H2_0, M0, M1, M2, M3, M4, T_9, T_10, H0_1, M5) + BR next + +TEXT ·hasVMSLFacility(SB), NOSPLIT, $24-1 + MOVD $x-24(SP), R1 + XC $24, 0(R1), 0(R1) // clear the storage + MOVD $2, R0 // R0 is the number of double words stored -1 + WORD $0xB2B01000 // STFLE 0(R1) + XOR R0, R0 // reset the value of R0 + MOVBZ z-8(SP), R1 + AND $0x01, R1 + BEQ novmsl + +vectorinstalled: + // check if the vector instruction has been enabled + VLEIB $0, $0xF, V16 + VLGVB $0, V16, R1 + CMPBNE R1, $0xF, novmsl + MOVB $1, ret+0(FP) // have vx + RET + +novmsl: + MOVB $0, ret+0(FP) // no vx + RET diff --git a/vendor/golang.org/x/crypto/poly1305/vectors_test.go b/vendor/golang.org/x/crypto/poly1305/vectors_test.go new file mode 100644 index 00000000..18d7ff8e --- /dev/null +++ b/vendor/golang.org/x/crypto/poly1305/vectors_test.go @@ -0,0 +1,2943 @@ +// 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 + +var testData = [...]test{ + // edge cases + { + // see https://go-review.googlesource.com/#/c/30101/ + key: "3b3a29e93b213a5c5c3b3b053a3a8c0d00000000000000000000000000000000", + tag: "6dc18b8c344cd79927118bbe84b7f314", + in: "81d8b2e46a25213b58fee4213a2a28e921c12a9632516d3b73272727becf2129", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "04000000000000000000000000000000", // (2¹³⁰-1) % (2¹³⁰-5) + in: "ffffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "faffffffffffffffffffffffffffffff", // (2¹³⁰-6) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (2¹³⁰-5) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "f9ffffffffffffffffffffffffffffff", // (2*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (2*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "f8ffffffffffffffffffffffffffffff", // (3*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (3*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "f7ffffffffffffffffffffffffffffff", // (4*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (4*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "f3ffffffffffffffffffffffffffffff", // (8*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (8*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "ebffffffffffffffffffffffffffffff", // (16*(2¹³⁰-6)) % (2¹³⁰-5) + in: "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "faffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + { + key: "0100000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", // (16*(2¹³⁰-5)) % (2¹³⁰-5) + in: "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "fbffffffffffffffffffffffffffffff" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + }, + // original smoke tests + { + key: "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + tag: "a6f745008f81c916a20dcc74eef2b2f0", + in: "48656c6c6f20776f726c6421", + }, + { + key: "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + tag: "49ec78090e481ec6c26b33b91ccc0307", + in: "0000000000000000000000000000000000000000000000000000000000000000", + }, + { + key: "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + tag: "da84bcab02676c38cdb015604274c2aa", + in: "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000", + }, + { + key: "0000000000000000000000000000000000000000000000000000000000000000", + tag: "00000000000000000000000000000000", + in: "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000000000" + + "000000000000000000000000000000000000000000000000000000", + }, + // randomly generated + { + key: "52fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649", + tag: "9566c74d10037c4d7bbb0407d1e2c649", + in: "", + }, + { + key: "81855ad8681d0d86d1e91e00167939cb6694d2c422acd208a0072939487f6999", + tag: "eaa270caaa12faa39b797374a4b8a420", + in: "eb", + }, + { + key: "9d18a44784045d87f3c67cf22746e995af5a25367951baa2ff6cd471c483f15f", + tag: "dbea66e1da48a8f822887c6162c2acf1", + in: "b90b", + }, + { + key: "adb37c5821b6d95526a41a9504680b4e7c8b763a1b1d49d4955c848621632525", + tag: "6ac09aaa88c32ee95a7198376f16abdb", + in: "3fec73", + }, + { + key: "8dd7a9e28bf921119c160f0702448615bbda08313f6a8eb668d20bf505987592", + tag: "b1443487f97fe340b04a74719ed4de68", + in: "1e668a5b", + }, + { + key: "df2c7fc4844592d2572bcd0668d2d6c52f5054e2d0836bf84c7174cb7476364c", + tag: "7463be0f9d99a5348039e4afcbf4019c", + in: "c3dbd968b0", + }, + { + key: "f7172ed85794bb358b0c3b525da1786f9fff094279db1944ebd7a19d0f7bbacb", + tag: "2edaee3bcf303fd05609e131716f8157", + in: "e0255aa5b7d4", + }, + { + key: "4bec40f84c892b9bffd43629b0223beea5f4f74391f445d15afd4294040374f6", + tag: "965f18767420c1d94a4ef657e8d15e1e", + in: "924b98cbf8713f", + }, + { + key: "8d962d7c8d019192c24224e2cafccae3a61fb586b14323a6bc8f9e7df1d92933", + tag: "2bf4a33287dd6d87e1ed4282f7342b6a", + in: "3ff993933bea6f5b", + }, + { + key: "3af6de0374366c4719e43a1b067d89bc7f01f1f573981659a44ff17a4c7215a3", + tag: "c5e987b60373a48893c5af30acf2471f", + in: "b539eb1e5849c6077d", + }, + { + key: "bb5722f5717a289a266f97647981998ebea89c0b4b373970115e82ed6f4125c8", + tag: "19f0f640b309d168ea1b480e6a4faee5", + in: "fa7311e4d7defa922daa", + }, + { + key: "e7786667f7e936cd4f24abf7df866baa56038367ad6145de1ee8f4a8b0993ebd", + tag: "de75e5565d97834b9fa84ad568d31359", + in: "f8883a0ad8be9c3978b048", + }, + { + key: "83e56a156a8de563afa467d49dec6a40e9a1d007f033c2823061bdd0eaa59f8e", + tag: "de184a5a9b826aa203c5c017986d6690", + in: "4da6430105220d0b29688b73", + }, + { + key: "4b8ea0f3ca9936e8461f10d77c96ea80a7a665f606f6a63b7f3dfd2567c18979", + tag: "7478f18d9684905aa5d1a34ee67e4c84", + in: "e4d60f26686d9bf2fb26c901ff", + }, + { + key: "354cde1607ee294b39f32b7c7822ba64f84ab43ca0c6e6b91c1fd3be89904341", + tag: "3b2008a9c52b5308f5538b789ab5506f", + in: "79d3af4491a369012db92d184fc3", + }, + { + key: "9d1734ff5716428953bb6865fcf92b0c3a17c9028be9914eb7649c6c93478009", + tag: "71c8e76a67a505b7370b562ba15ba032", + in: "79d1830356f2a54c3deab2a4b4475d", + }, + { + key: "63afbe8fb56987c77f5818526f1814be823350eab13935f31d84484517e924ae", + tag: "1dc895f74f866bdb3edf6c4430829c1c", + in: "f78ae151c00755925836b7075885650c", + }, + { + key: "30ec29a3703934bf50a28da102975deda77e758579ea3dfe4136abf752b3b827", + tag: "afca2b3ba7b0e1a928001966883e9b16", + in: "1d03e944b3c9db366b75045f8efd69d22ae5411947cb553d7694267aef4e" + + "bcea406b32d6108bd68584f57e37caac6e33feaa3263a399437024ba9c9b" + + "14678a274f01a910ae295f6efbfe5f5abf44ccde263b5606633e2bf0006f" + + "28295d7d39069f01a239c4365854c3af7f6b41d631f92b9a8d12f4125732" + + "5fff332f7576b0620556304a3e3eae14c28d0cea39d2901a52720da85ca1" + + "e4b38eaf3f", + }, + { + key: "44c6c6ef8362f2f54fc00e09d6fc25640854c15dfcacaa8a2cecce5a3aba53ab", + tag: "6f2a09aa76c9b76774e31ec02dcf7991", + in: "705b18db94b4d338a5143e63408d8724b0cf3fae17a3f79be1072fb63c35" + + "d6042c4160f38ee9e2a9f3fb4ffb0019b454d522b5ffa17604193fb89667" + + "10a7960732ca52cf53c3f520c889b79bf504cfb57c7601232d589baccea9" + + "d6e263e25c27741d3f6c62cbbb15d9afbcbf7f7da41ab0408e3969c2e2cd" + + "cf233438bf1774ace7709a4f091e9a83fdeae0ec55eb233a9b5394cb3c78" + + "56b546d313c8a3b4c1c0e05447f4ba370eb36dbcfdec90b302dcdc3b9ef5" + + "22e2a6f1ed0afec1f8e20faabedf6b162e717d3a748a58677a0c56348f89" + + "21a266b11d0f334c62fe52ba53af19779cb2948b6570ffa0b773963c130a" + + "d797ddea", + }, + { + key: "fe4e3ad29b5125210f0ef1c314090f07c79a6f571c246f3e9ac0b7413ef110bd", + tag: "27381e3fc2a356103fb796f107d826e7", + in: "58b00ce73bff706f7ff4b6f44090a32711f3208e4e4b89cb5165ce64002c" + + "bd9c2887aa113df2468928d5a23b9ca740f80c9382d9c6034ad2960c7965" + + "03e1ce221725f50caf1fbfe831b10b7bf5b15c47a53dbf8e7dcafc9e1386" + + "47a4b44ed4bce964ed47f74aa594468ced323cb76f0d3fac476c9fb03fc9" + + "228fbae88fd580663a0454b68312207f0a3b584c62316492b49753b5d502" + + "7ce15a4f0a58250d8fb50e77f2bf4f0152e5d49435807f9d4b97be6fb779" + + "70466a5626fe33408cf9e88e2c797408a32d29416baf206a329cfffd4a75" + + "e498320982c85aad70384859c05a4b13a1d5b2f5bfef5a6ed92da482caa9" + + "568e5b6fe9d8a9ddd9eb09277b92cef9046efa18500944cbe800a0b1527e" + + "a6", + }, + { + key: "4729a861d2f6497a3235c37f4192779ec1d96b3b1c5424fce0b727b03072e641", + tag: "0173965669fb9de88d38a827a0271271", + in: "5a761f03abaa40abc9448fddeb2191d945c04767af847afd0edb5d8857b7" + + "99acb18e4affabe3037ffe7fa68aa8af5e39cc416e734d373c5ebebc9cdc" + + "c595bcce3c7bd3d8df93fab7e125ddebafe65a31bd5d41e2d2ce9c2b1789" + + "2f0fea1931a290220777a93143dfdcbfa68406e877073ff08834e197a403" + + "4aa48afa3f85b8a62708caebbac880b5b89b93da53810164402104e648b6" + + "226a1b78021851f5d9ac0f313a89ddfc454c5f8f72ac89b38b19f53784c1" + + "9e9beac03c875a27db029de37ae37a42318813487685929359ca8c5eb94e" + + "152dc1af42ea3d1676c1bdd19ab8e2925c6daee4de5ef9f9dcf08dfcbd02" + + "b80809398585928a0f7de50be1a6dc1d5768e8537988fddce562e9b948c9" + + "18bba3e933e5c400cde5e60c5ead6fc7ae77ba1d259b188a4b21c86fbc23" + + "d728b45347eada650af24c56d0800a8691332088a805bd55c446e25eb075" + + "90bafcccbec6177536401d9a2b7f512b54bfc9d00532adf5aaa7c3a96bc5" + + "9b489f77d9042c5bce26b163defde5ee6a0fbb3e9346cef81f0ae9515ef3" + + "0fa47a364e75aea9e111d596e685a591121966e031650d510354aa845580" + + "ff560760fd36514ca197c875f1d02d9216eba7627e2398322eb5cf43d72b" + + "d2e5b887d4630fb8d4747ead6eb82acd1c5b078143ee26a586ad23139d50" + + "41723470bf24a865837c", + }, + { + key: "9123461c41f5ff99aa99ce24eb4d788576e3336e65491622558fdf297b9fa007", + tag: "1eb0cdad9237905250d30a24fe172a34", + in: "864bafd7cd4ca1b2fb5766ab431a032b72b9a7e937ed648d0801f29055d3" + + "090d2463718254f9442483c7b98b938045da519843854b0ed3f7ba951a49" + + "3f321f0966603022c1dfc579b99ed9d20d573ad53171c8fef7f1f4e4613b" + + "b365b2ebb44f0ffb6907136385cdc838f0bdd4c812f042577410aca008c2" + + "afbc4c79c62572e20f8ed94ee62b4de7aa1cc84c887e1f7c31e927dfe52a" + + "5f8f46627eb5d3a4fe16fafce23623e196c9dfff7fbaff4ffe94f4589733" + + "e563e19d3045aad3e226488ac02cca4291aed169dce5039d6ab00e40f67a" + + "ab29332de1448b35507c7c8a09c4db07105dc31003620405da3b2169f5a9" + + "10c9d0096e5e3ef1b570680746acd0cc7760331b663138d6d342b051b5df" + + "410637cf7aee9b0c8c10a8f9980630f34ce001c0ab7ac65e502d39b216cb" + + "c50e73a32eaf936401e2506bd8b82c30d346bc4b2fa319f245a8657ec122" + + "eaf4ad5425c249ee160e17b95541c2aee5df820ac85de3f8e784870fd87a" + + "36cc0d163833df636613a9cc947437b6592835b9f6f4f8c0e70dbeebae7b" + + "14cdb9bc41033aa5baf40d45e24d72eac4a28e3ca030c9937ab8409a7cbf" + + "05ae21f97425254543d94d115900b90ae703b97d9856d2441d14ba49a677" + + "de8b18cb454b99ddd9daa7ccbb7500dae4e2e5df8cf3859ebddada6745fb" + + "a6a04c5c37c7ca35036f11732ce8bc27b48868611fc73c82a491bfabd7a1" + + "9df50fdc78a55dbbc2fd37f9296566557fab885b039f30e706f0cd5961e1" + + "9b642221db44a69497b8ad99408fe1e037c68bf7c5e5de1d2c68192348ec" + + "1189fb2e36973cef09ff14be23922801f6eaee41409158b45f2dec82d17c" + + "aaba160cd6", + }, + { + key: "40ff73495fe4a05ce1202ca7287ed3235b95e69f571fa5e656aaa51fae1ebdd7", + tag: "2e619d8ea81b77484e4fddeb29844e4b", + in: "aa6269c2ec7f4057b33593bc84888c970fd528d4a99a1eab9d2420134537" + + "cd6d02282e0981e140232a4a87383a21d1845c408ad757043813032a0bd5" + + "a30dcca6e3aa2df04715d879279a96879a4f3690ac2025a60c7db15e0501" + + "ebc34b734355fe4a059bd3899d920e95f1c46d432f9b08e64d7f9b38965d" + + "5a77a7ac183c3833e1a3425ead69d4f975012fd1a49ed832f69e6e9c63b4" + + "53ec049c9e7a5cf944232d10353f64434abae060f6506ad3fdb1f4415b0a" + + "f9ce8c208bc20ee526741539fa3203c77ecba410fd6718f227e0b430f9bc" + + "b049a3d38540dc222969120ce80f2007cd42a708a721aa29987b45d4e428" + + "811984ecad349cc35dd93515cefe0b002cee5e71c47935e281ebfc4b8b65" + + "2b69ccb092e55a20f1b9f97d046296124621928739a86671cc180152b953" + + "e3bf9d19f825c3dd54ae1688e49efb5efe65dcdad34bc860010e7c8c997c" + + "d5f9e320ca7d39d4ba801a175b1c76f057832f3f36d7d893e216e4c7bbdb" + + "548d0ba48449330027368b34f9c69776b4591532da1c5be68ef4eebe8cb8" + + "fa7dc5483fb70c2c896334cb1f9cb5dfe044fa086197ff5dfd02f2ba3884" + + "c53dd718c8560da743a8e9d4aeae20ccef002d82ca352592b8d8f2a8df3b" + + "0c35f15b9b370dca80d4ca8e9a133eb52094f2dd5c08731f52315d828846" + + "e37df68fd10658b480f2ac84233633957e688e924ffe3713b52c76fd8a56" + + "da8bb07daa8eb4eb8f7334f99256e2766a4109150eed424f0f743543cdea" + + "66e5baaa03edc918e8305bb19fc0c6b4ddb4aa3886cb5090940fc6d4cabe" + + "2153809e4ed60a0e2af07f1b2a6bb5a6017a578a27cbdc20a1759f76b088" + + "9a83ce25ce3ca91a4eb5c2f8580819da04d02c41770c01746de44f3db6e3" + + "402e7873db7635516e87b33e4b412ba3df68544920f5ea27ec097710954f" + + "42158bdba66d4814c064b4112538676095467c89ba98e6a543758d7093a4" + + "94df", + }, + { + key: "5cc36d09c7a6472a41f29c380a987b1ecdcf84765f4e5d3ceefc1c02181f570f", + tag: "0d57b8cbea8090df0541354673dcb4e0", + in: "44fcd629f08dc1ef53c9ae0d8869fe67fdc7a2c67b425f13c5be8d9f630c" + + "1d063c02fd75cf64c1aec9d2e2ef6e6431d5f5ad0489078dc61f46494dcc" + + "f403dad7f094170d2c3e29c198b0f341e284c4be8fa60c1a478d6bd55dd2" + + "c04dad86d2053d5d25b014e3d8b64322cdcb5004faa46cfa2d6ad2ff933b" + + "c3bd9a5a74660af3d048a9a43634c0250427d9a6219197a3f3633f841753" + + "ba7c27f3619f387b6b1a6cb9c1dc227674aa020724d137da2cb87b1615d5" + + "12974fa4747dd1e17d02c9462a44fec150ca3a8f99cc1e4953365e429956" + + "5e108535b1f62e1d4ba18e17a52164418bfd1a933f7fb3a126c860830a87" + + "293d9271da736e4398c1e37fb75c4bf02786e1faf4b610cd1377fbb9ae18" + + "0655a0abefbad700c09473469f1eca5a66d53fa3dc7cd3e7c3b0411d7e14" + + "5f96eb9654ab94913dda503a50f9e773842f4d2a5faa60869bf365830511" + + "f2ededd03e0a73000edb60c9a29a5f5e194cf3b5667a694690384599d116" + + "f8d2fd93b2aed55b7d44b5b054f3f38e788e4fdf36e591568c41d1052cad" + + "0fcb68ca4c4bf5090d57df9db6f0d91dd8b11b804f331adb7efb087a5604" + + "e9e22b4d54db40bcbc6e272ff5eaddfc1471459e59f0554c58251342134a" + + "8daaef1498069ba581ef1da2510be92843487a4eb8111c79a6f0195fc38a" + + "d6aee93c1df2b5897eaa38ad8f47ab2fe0e3aa3e6accbfd4c16d46843318" + + "5fc61c861b96ca65e34d31f24d6f56ee85092314a4d7656205c15322f1c9" + + "7613c079eae292ba966e10d1e700164e518b243f424c46f9ea63db1c2c34" + + "b512c403c128ee19030a6226517b805a072512a5e4cd274b7fd1fa23f830" + + "058208ff1a063b41039c74036b5b3da8b1a0b93135a710352da0f6c31203" + + "a09d1f2329651bb3ab3984ab591f2247e71cd44835e7a1a1b66d8595f7ae" + + "f9bf39d1417d2d31ea3599d405ff4b5999a86f52f3259b452909b57937d8" + + "5364d6c23deb4f14e0d9fcee9184df5994fdc11f045c025c8d561adb0e7d" + + "fd4748fd4b20f84e53322471a410cdb3fd88e48b2e7eb7ae5dae994cb5ea" + + "e3eaf21cf9005db560d6d22e4d9b97d7e9e488751afcd72aa176c0fcde93" + + "16f676fd527d9c42105b851639f09ea70533d26fc60cbeb4b76ed554fc99" + + "177620b28ca6f56a716f8cb384", + }, + { + key: "811c3e356e7c793acf114c624dc86ace38e67bff2a60e5b2a6c20723c1b9f003", + tag: "c6e59044cefc43ee681c3eed872d02b3", + in: "e115b304c023792448794546a2474f04294d7a616215e5dd6c40a65bb6ed" + + "b508c3680b14c176c327fdfb1ee21962c0006b7deb4e5de87db21989d13c" + + "3ab0462d5d2a52ef4ca0d366ae06a314f50e3a21d9247f814037798cc5e1" + + "0a63de027477decdeb8a8e0c279299272490106ddf8683126f60d35772c6" + + "dfc744b0adbfd5dcf118c4f2b06cfaf077881d733a5e643b7c46976647d1" + + "c1d3f8f6237c6218fa86fb47080b1f7966137667bd6661660c43b75b6339" + + "0b514bbe491aa46b524bde1c5b7456255fb214c3f74907b7ce1cba94210b" + + "78b5e68f049fcb002b96a5d38d59df6e977d587abb42d0972d5f3ffc898b" + + "3cbec26f104255761aee1b8a232d703585dd276ee1f43c8cd7e92a993eb1" + + "5107d02f59ba75f8dd1442ee37786ddb902deb88dd0ebdbf229fb25a9dca" + + "86d0ce46a278a45f5517bff2c049cc959a227dcdd3aca677e96ce84390e9" + + "b9a28e0988777331847a59f1225b027a66c1421422683dd6081af95e16f2" + + "48ab03da494112449ce7bdace6c988292f95699bb5e4d9c8d250aa28a6df" + + "44c0c265156deb27e9476a0a4af44f34bdf631b4af1146afe34ea988fc95" + + "3e71fc21ce60b3962313000fe46d757109281f6e55bc950200d0834ceb5c" + + "41553afd12576f3fbb9a8e05883ccc51c9a1269b6d8e9d27123dce5d0bd6" + + "db649c6fea06b4e4e9dea8d2d17709dc50ae8aa38231fd409e9580e255fe" + + "2bf59e6e1b6e310610ea4881206262be76120d6c97db969e003947f08bad" + + "8fa731f149397c47d2c964e84f090e77e19046277e18cd8917c48a776c9d" + + "e627b6656203b522c60e97cc61914621c564243913ae643f1c9c9e0ad00a" + + "14f66eaa45844229ecc35abb2637317ae5d5e338c68691bea8fa1fd469b7" + + "b54d0fccd730c1284ec7e6fccdec800b8fa67e6e55ac574f1e53a65ab976" + + "4c218a404184793cc9892308e296b334c85f7097edc16927c2451c4cd7e5" + + "3f239aa4f4c83241bde178f692898b1ece2dbcb19a97e64c4710326528f2" + + "4b099d0b674bd614fad307d9b9440adab32117f0f15b1450277b00eb366e" + + "0260fca84c1d27e50a1116d2ce16c8f5eb212c77c1a84425744ea3195edb" + + "b54c970b77e090b644942d43fe8c4546a158bad7620217a40e34b9bb84d1" + + "89eff32b20ef3f015714dbb1f150015d6eeb84cbccbd3fffa63bde89", + }, + { + key: "f33691f5db2dea41e1e608af3ff39f3a6988dba204ce1b09214475ae0ea864b8", + tag: "6e50e70411201378c8d67857d7b631d2", + in: "439bc9ea10db4d2b08c7fcf2e8bd89fa9844f8061d462e28f174489e7514" + + "0f84e842040141cc59ce38f9551850cfbdfac2d75337d155090d70d0d930" + + "04340bdfe60062f17c53f3c9005b9995a0feb49f6bef8eaff80f4feb7ef3" + + "f2181733a4b43b6ac43a5130a73a9b3c2cbc93bd296cd5f48c9df022b6c8" + + "2bb752bc21e3d8379be31328aa32edc11efc8a4b4b3f370ee8c870cd281d" + + "614e6bc2c0a5ca303bc48696a3bd574ee34738de4c4c29910f8feb7557bf" + + "ffcfe7428b4703144bd6d7fe5b3f5de748918553df5453b3c6001696f3de" + + "0137e454aadf30cedfb6be36b0b908a38409f1a2dc202fc285610765e4c8" + + "6414692bf4bde20ed899e97727b7ea1d95d7c621717c560f1d260ab3624e" + + "d6168d77c483dd5ce0d234049017795f2e5a7569d7ad323c50a5b1170337" + + "4174a9977026c20cd52c10b72f14e0569a684a3dcf2ccbc148fd3db506e2" + + "8d24f6c55544cb3980a36e86747adc89ebad78d1630618d113fa445f8625" + + "b583cd7be33913c30c419d047cf3baf40fd05219a1fcec717b87a65fa022" + + "1a3aa8143062d77588168019454240ae3d37640996f2967810459bc658df" + + "e556de4d07263dc3d9158ec242008226d1c6aea7f0846e12ce2d316e80da" + + "522343264ec9451ec23aaaa367d640faad4af3d44d6d86544ade34c93518" + + "2843f6b4d1c934996778affa9ee962e7dfef5e70d933d4309f0f343e9606" + + "1b91b11ac380a9675e17a96099fe411bedc28a298cd78d5496e28fbbd4f5" + + "b0a27735d1144348e22be5b75724d8f125e99c4cb4e9c3a1f0b4e9da5146" + + "e6afaa33d02fda74bf58a8badee2b634b989c01755afa6ab20ee494c6ae4" + + "c2c6f17af6b53b61d2947d83a18eb3b8a1612aad5d3ea7e8e35f325c9168" + + "ac490f22cb713ddb61fbd96011c5849ac8e2fcd42db820349bdf9157dcc0" + + "0d9f9ed9c099b10c7194d48b623b0df43759734b2a2e5f8a35e7192bf9a0" + + "03dcb9d16a54bd84d922f85b6021b28aacc5264fe9e83deb48f18f864cbd" + + "367eb163d39c45b0eb907311a2a4b09fb26109088df782ce031b02f3caff" + + "d2dbe25b1cbde9f35ba7c47292a4fd49e7def7a28824f3dfda259a86c3de" + + "59257c255c712686ee47d128a55c7b9e8c546035eab7e2da420f32ed5c94" + + "bc12a34dc68eb99257a7ea03b69d6c760b0681fa24e4ca97b7c377182ab5" + + "fee30a278b08c44c988a8f925af2997883111c750d176b432735868208f4" + + "0de7137331b544f2d28040a3581d195e82811c945c3f9fde68fc21b36a44" + + "e1cfa2d8eb625f3102461539b3f13c660936a5ddb29a0ae791fbf52c2f69" + + "7bd334653f3605b362d91cd78569b41dbd09b2a5892440b5097fa08d0b4b" + + "291fc5b934585dd8d5adc80d573fdd194b2eae26dfc49f5e51c1f1607d7e" + + "87740702f244bf39ca1d52423e0ae84891dfdf4f43ef984c7a5f293a2007" + + "a1e00e39c757f064518953f55621f955986f63", + }, + { + key: "d115b6ac998a65b48b3dae5977abaf985258d3d1cfe1616cec3d6a77f7a75785", + tag: "b431c9318ec2769fc8ee8f5fc3c079c3", + in: "7e7eb43839a6d7616b8a7b1fb7144817904342a9bd34167051162941a6b1" + + "b85db5e587f76e4a53211755d5ab29c11822d7711a97b3f1ff5b21f2485d" + + "9c86241fb56cdd6796245d3112df11ad9a7344db44d09934c4efb280ed65" + + "80cfcafb5c97a32993cbbf4917183e0b7bb38f2ce2479c28e1d39f673962" + + "17a7010448dfd39a4e7f406c8bd2d804f993bb410fffa4eb57518a531ecf" + + "259a8af068230acb826d9ffc20ee0fc43885221a321e3928971bb28615f0" + + "d9f099f5b68a80503a910fdba0bc643c60b64837900be38770b6b30c362c" + + "4580722b5dbb1b9c8cd02a18fd7b5661d2c4d28aa941c50af6655c826690" + + "37312fbf9f1cf4adb0b9400532755011b40e8252bd0e3c7a22efb0ef9122" + + "1e04b4aa8316d4a4ffeaa11909d38cc264650e7ca416835ded0953f39e29" + + "b01d3a33bba454760fb0a96d9fe50b3e42c95271e57840380d1fd39a375b" + + "3e5513a31a4b80a2dad8731d4fd1ced5ff61e1fbe8ff3ff90a277e6b5631" + + "f99f046c4c3c66158554f61af2ede73aede97e94b1d1f129aaadf9b53548" + + "553cc2304103e245b77701f134d94d2a3658f2b41108c5a519c2c8f450db" + + "027824f1c0ab94010589a4139ff521938b4f0c7bf0986585f535b6e292e5" + + "b3ded23bf81cec17c8420fe67a449e508864e4cbb7eaf335975668f013e9" + + "da70b33bd52a72094a8f03762ea7440ce9fcd10e251837cfc9ccc1a8cc47" + + "0c67379f6a32f16cf70ea8c19d1a67779a9b2d2b379665e0e908a88b26e7" + + "8c9f94f17acefa6d5feb70a7095e0297c53e091cf98df132a23a5ce5aa72" + + "59f1154b92e079f0b6f95d2a38aa5d62a2fd97c12ee7b085e57cc4652863" + + "8defacc1e70c3aceab82a9fa04e6aa70f5fbfd19de075bee4e3aac4a87d0" + + "ad0226a463a554816f1ebac08f30f4c3a93fa85d79b92f0da06348b4f008" + + "880fac2df0f768d8f9d082f5a747afb0f62eb29c89d926de9fc491921474" + + "1d8647c67d57ac55f94751389ee466bbd44dbe186f2f38abbc61a0425613" + + "e9b6a64e6bcb45a2e2bb783b9103483643d5610a7e2dcdb10b5d78423285" + + "506b42a99b00a4fb7b619b4526bb4ec78299dd01ad894fde2f053e18c55b" + + "6047f86333f2690c2cb8e87d9834ab8a5e339aa346e4d9952ed62dc083e3" + + "b11a823a67f23fec099a033f127ebe8626a89fa1a5a6b3520aa0d215a8e7" + + "dea3af37907686c16521739a95d6c532cc259c497bf397fceaea49cd46b9" + + "ad5c1b39a36fdd2f0d2225fef1b6ca2bb73fe604646c10ba4c572ab13a26" + + "559ededc98f5a34c874cc25621e65ba4852529b5a4e9c1b2bf8e1a8f8ff0" + + "5a31095b84696c6381eb9ad37ac0db184fe5fccf3554e514946a33cabe6f" + + "4d617b549d28ad1cc4642dac96e0215ee1596481600d3619e8f45e2c9ae1" + + "da834d44aca216bba0efef6254503ca90339f2d7ca508b2722d50c08def8" + + "a736590fa44855cd9eb9979c743783aa26e633696739f2ae25ff7b72ceb2" + + "4dff4455b85bbd675c8cb71ad18386dc58c371bdf37b4b3875b98a9423ff" + + "3becfc0d0ba2aacab3ee7683cb3b345095fefcaca5751ca793da63c89428", + }, + { + key: "f3717306b9729be998cdb2c9d856306c5ae3d89da2cdcef12f86f6110c98d873", + tag: "907dba0f4849c7cf4570b5128b5f31d5", + in: "079572187d4559f24d8e48dc366441acf226a4db79e214ec3ee288acc349" + + "887e2e377419bcafa377d0151497b52e4d9cf2a02b0fc91ad9516482bdf6" + + "eccd1497954b53241bfb0bc5c04cc45045c6251f23a510060fee32721872" + + "bbc95cd8d400dff00bcac2ecce6229c7d73d8f85ed5a87afdccf6dedd299" + + "2d5c7b5b8090c47c737ded036ff0e9aedf02a2242fd9820be618b9601e73" + + "d3ba5d8f1ae9805cfd2306251704bc74e3546997f109f1dfae20c03ff31f" + + "17564769aa49f01233c9c4b79f90fa3d1433d18cdc497914046ad77d2792" + + "2588a7d0e61d4258d7d80cdab8503e3111ddca22cf7f39c1f80f1e16a68d" + + "9e21db8b53dd316dfa4233cb453a39a90101c60efc08514a3057db007e96" + + "507745bd4a0764ed8717a250bffb5fd1ea58474bdfb5b869681939693926" + + "40d832a3387ed4ac9cdab0d2af8fcb51b86e4d927097f1e79b5af96574ec" + + "d59d0dd150a0208978c41de28ad6cadf72a49279cffd6dc281c640f2e294" + + "4cde49a13ed390da1dd92e3011ce0f4a0863375a9db3f67fca1e3b8288a0" + + "78611161d7cb668ecdb932e1ff3733982c8c460eeeff2bca46c96e8a02cf" + + "b55d770940de556373a4dd676e3a0dd66f1280c8cb77a85136b3f003fab4" + + "887dad548de7bfe6488ae55e7a71da4097db03900d4b94e776a939530328" + + "83492da900b2a6c3e73d7a6f12ee30c9dd06cc34e5a3893976eb1de5864d" + + "32e792ac02e68d052d9d0cfc7cfb40b77728422f6c26cf68987c6b40fcfe" + + "9d660abc657360eb129de11bd70af5eb8fe350af2c27a6ece2cdf81b94c8" + + "0e68e8c51106497cfa5171236efe2d71d76b5dff3352af9b407dc5aab60f" + + "46b5683646f5b28732b7c750d351a08a507243d8e437cc4bef13a3edaa20" + + "5fc4e9968b4e563fa0dc965ba20b8e48bc188a321b16d3213bed69647512" + + "7a20afc1a3680ef261df6d37b017dee05cfc3a42e4130216e5540cf715c4" + + "e638d7d615c50bef576eeb19b3b15b2c2b454dfcef2b18161a143ddf52fc" + + "8e88fa71cbe34c92cd4b5a0adc81e5c33e11d2721bc1b95a9e693ac3cabc" + + "490889a8a42bf7e22375b679e8598c8faef22a006ed2da8ab1c08aaed2f5" + + "6d6f26649036335c0881bfec1e3a5346335c3b3707ee92173f1a7a3305c2" + + "933f78e995da8f1df64daf12b81ce23c8813c27fd4551103dc33561c2e80" + + "45b6b6770fa03498fd359a104884699d628020173edbcc4398b977e456e4" + + "885964840466176a490e7c513ba5d66090277c1ab1632a995a54f555a452" + + "1170a000507865b6650730aa6d6050a55959102836fff3d37e4773340e59" + + "2e56951ff9652519de4421d9c5b63edbeb30a3852a1ea110a9a29721aee3" + + "23d5a306de1624cecc87badc47aa87f489635d2fb60bff62ba67f5257999" + + "6af0a1f1a6fbcd8704e119196fcc289a6db6a4170a2cae31a1d30744b702" + + "2536d1526d41659c2dcc8b39c26aecfc0f8a707136d81b2827a158fd7386" + + "a537514471c213a8c859016748e0264cf3fbde10f40c620840ec4df99432" + + "e2b9e1e368e33f126ec40c572e841c2618d49d4eb098b9533b1f4ae00b46" + + "8d15de8c8ab6d0b650e599576f2bd90a124c9c6a0f911fd1bd8253bac272" + + "942cbdf8864f3747ff7f09d8a5a9d8599be7ee1744e5f1faf3e526cd2a06" + + "b157527272af9d38565957c9ce663c295766c0e0e464971c6282b70d4c0c" + + "1fb3b69856b34c089ad2b2c745f5a033cee1429c5b855581ee285278893c" + + "43a5968d9c28384b7abe8d072ba69089c938685cb1eab461f05314ad6d06" + + "eaa58512f8738bde35b7b15ef359dd2e8753cb1ed6", + }, + { + key: "9772c1a4b74cbf53586e5df04369b35f1fdca390565872251bc6844bc81bda88", + tag: "68eb7fc459ecc3be819485001ab438dc", + in: "e115cc2f33e367cb85c01a914b3a512404ad6a98b5b0c3a211d4bffd5802" + + "ee43b3fb07451c74524ec8b4eddbb41ca33dd6e49791875d716a44bec97b" + + "7c2d4546616939ffa3b1ab9b8ba1d1a637e7c985cc922606caa0453085e3" + + "5f2fe0bd2de129d1d1856ade975a3281a62965927d8bb695e54514e69558" + + "89361a2a00a1b24e62bda78d0b71a0d40147016fcdaf1a702331dda8e678" + + "d8f476dcc91698da1688c610ec0cb1d9b8fbcd45dfde6d1503ba60a01337" + + "ae5b2f5c854a82c3087779babd2e522dd92f4718cd9f8c649ac226745ca2" + + "fa1696442764758f67cd926369578ae87612790dc56ed9cda935281a490e" + + "5c984950ec7a4e930520d273a69da4ed3a330e532508e26f942961fed0e3" + + "efeed52a7b96250d723155aa39a8ae85131c255c32bf406b647de1a37fba" + + "dc61e302bb5b70adec4505ee66b3a1d1b7bfe9c58b11e53ad556d56e5807" + + "017bb30b71be94e8f86aaf1496e8b8d6db75ec0afbe1cd336c23963c745d" + + "7b4ba1787ceb30728f1762b46f6eaad5064c8029d29b86266b87f93142a2" + + "74f519f3281d8c1cb43c23eb184ae41f3f625cf624b05a48d73cd7783fdf" + + "14954a03ec1a930e9a954424eff030e3f15357de4c19983f484619a0e9e2" + + "b67221cf965e9aa8d8926595c793adfe0181050df8b845ce648a66df532f" + + "78b10c83ecc86374a4f8abf8edcc303654bafd3dcc7de9c77a0a9d1d98fb" + + "121534b47d16f75b55fdc2a5e2e6799f8a2f8000d4292282e56863ae422a" + + "5779900ad6881b78946e750d7777f33f2f013a75c19615632c0e40b98338" + + "1e9b8d35a26abe30242c45662eebb157e6d7a8a5519de60268ac289b8295" + + "5d4feb47b9eef6da65031c6f52c2c4f5baa36fce3618b6a331f1e8bdd621" + + "48954fcf0846afeeb0a6cadb495c909a7fe671b021d5b0b4669961052187" + + "d01b67d44218471bfb04c1a3d82bf7b776208013fc8adabaefb11719f7a7" + + "e6cb0b92d4cc39b403ceb56bd806cbdcc9ee75362ab4aaeb760e170fdc6a" + + "23c038d45f465d8ec8519af8b0aad2eb5fae2972c603ed35ff8e46644803" + + "fc042ff8044540280766e35d8aaddcaa81e7c0c7eba28674f710492924c6" + + "1743da4d241e12b0c519910d4e31de332c2672ea77c9a3d5c60cd78a35d7" + + "924fda105b6f0a7cc11523157982418405be0bacf554b6398aeb9a1a3b12" + + "fe411c09e9bfb66416a47dd51cbd29abf8fbbd264dd57ba21a388c7e19e8" + + "12e66768b2584ad8471bef36245881fc04a22d9900a246668592ca35cfc3" + + "a8faf77da494df65f7d5c3daa129b7c98cef57e0826dee394eb927b3d6b3" + + "a3c42fa2576dcc6efd1259b6819da9544c82728276b324a36121a519aee5" + + "ae850738a44349cdec1220a6a933808aee44ba48ce46ec8fb7d897bd9e6b" + + "c4c325a27d1b457eb6be5c1806cd301c5d874d2e863fb0a01cbd3e1f5b0f" + + "8e0c771fca0c0b14042a7b0f3ae6264294a82212119b73821dcfbbfd85bb" + + "625b6f75e4dc0ee0292ab4f17daf1d507e6c97364260480d406bd43b7d8e" + + "8c2f26672a916321b482d5fa7166e282bfeed9b3598c8f8c19d2f8c8b98d" + + "f24c2500c8ad41cd6ed3f2835737916d846f1a6406cda1125ed7740fe301" + + "d1144559b7c95fa407599ae40a795226513153f86c9b8abe7d8aa6963c99" + + "5646ec586cbf20a03a698cc0681b7bd333402d00fa8e15cb32300b5a24ea" + + "316c5e1df67de78891846cb9183a4b112c3bcc17bcaa5fecd6c1dbbf6ef8" + + "272d9269e7f0ba9f17050a6aa5f11cb28874360396ab647941f2c9a85cb0" + + "6a969919b16997b0827af8f909c614545f1ad638ebb23109f6bab6b49b22" + + "b2285cabbb998b3e1bf42771b4d4e52330b224e5a1d63169ec85fe1c7dd2" + + "46dbafa6138448420f463d547a41c2b26026d4621b854bc7786ab3a0a93a" + + "e5390dd840f2454028b7c3bb87680f04f084089bbc8786ee42cf06904d01" + + "7e405144d2fae141599e2babe71abfbe7644fb25ec8a8a44a8928ff77a59" + + "a3e235de6bd7c7b803cf3cf60435e473e3315f02d7292b1c3f5a19c93646" + + "3cc4ccd6b24961083756f86ffa107322c5c7dd8d2e4ca0466f6725e8a35b" + + "574f0439f34ca52a393b2f017d2503ba2018fb4a0991fddc1949832d370a" + + "27c42e", + }, + { + key: "d18a328b63a1d0f34e987682fe6ca3d48b4834b4312a17e99b3d88827b8d2238", + tag: "938b43b80cb3935e39b21dd8ba133cf8", + in: "bc2b0baf92580ee6c5efe640f2a029a791a3c77bec459be74cbc30931508" + + "d9f312c3a0944212831cbe4fc92e8f107f2f750c91bcc09f7624fa9a09b4" + + "9b7712cf5d619ea9da100fc23068ae2f4e353047e3956b215884bdb12235" + + "3f06b8ee98f36c3212493d61ae9ce151cd0453f3075b18a12d7d73da3de7" + + "dc2d98376cfb420069ca8148c511ca6bbae57572394a3c615a6fefb30c5f" + + "d727f964b4065ac9ee252bdd2bcae3e70162fe0e8069974e073f0a093d45" + + "be52d7de16a8f5f65c548aa6525822ffb00dc642530fedf355f7188ef017" + + "56384760c80afb61ad903d10119a7d615ec4fbdc79c490160bdeaf200915" + + "e405f2a921a2380c0ab9d2ac1e4fdc8ec4b907368c004458598efac13dc7" + + "2751e7faded538e3dc8b16590cac9b7ec294da0ad53e22cb9c05d8ef494f" + + "a04f6ab7c843c867fbe3cf1b4eb146d65339b0b03392259f12627a8e98e8" + + "0f4896c30b8ecd210acb2365539a872541921dcd8e1e54caf4936dfc7e1f" + + "68f3bbce61d325b447a8cce7f0fcad28494f2e47dae46b136594b5dfca7a" + + "bdafd6856f91496c05b21079aa55aa8c41628220a2cf0cdd755893375b7b" + + "b13d914c9a1d1db4a18f8fa36c55e52d0342352052032fb62d32fcd51cb1" + + "ac46f44b06e682db5d96d583cda03b966c650c03ae53542e8da1066b6884" + + "4a7e2280c664415e413f270b1fdcfbb40b9daa6131d071ee7eb1553dc5b1" + + "a50677971223dc316d2d326d57cbd529c88698facdca425e2d5c6b10d7ae" + + "cae28b8890aa44ede9b9193dbe8d1d8aa1fa580ca384b57eadcbefc96dd8" + + "bfccbe3b855a96f1fd4913035f817b75954ef1827c7718aab24d353e41cb" + + "a73748e14e0c2750d5b6a9752125708cc7ee7a498c7fbadf4186e7f8fa93" + + "bfdf281a49400f877621651b8ba87edda5231e80b758564e75139b61b1a9" + + "9fb9ec694f928ab1f47c6c4287bd4182d1b2be053380616e98da06f3ef57" + + "b570ade17c51da1d602b6ebc5a638ebde30d99bf4f91d0e01557c7dcd8f7" + + "9e5120143c935fc699eb5616ccd3cac56b5f8a53ed9e6c47ba896bfefe71" + + "2004ad908c12cf6d954b83bec8fb0e641cc261ff8f542b86e62d90e227f2" + + "a5bd59c9d390c0dd857f6da2b7624787a0bb31908bae84896890b283da61" + + "d8ec4f56eea38b22b438d6374b42243f9c1d94288874e53ab90c554cc1f1" + + "d736acde67aff55007fd4b3becc4d0f3ddd96f10dc75255cb0327aa47076" + + "2b3a3a656e33c87b02a682658b6cd2a75d9c0462803c9bbffa51441501a0" + + "3a2fbb2344aa13d27ffb9e98704ea6720b6a9992e53449688cd74d0648fa" + + "e8e776b0ea6bf048b2ec05341e5948cab0af015328b284ae7bd89a5f763c" + + "eaf5ca3e647a9f5bff7197e4d357e4359fa5fe30709545453149be510e3b" + + "ff86beeba5110c79c0215fbe9ac9339a8ac7d41f7488588ab14ac657aaf7" + + "d5c03a353932bbb2b261f0e83f3526c5e8e0c2348a10ab4eed6ecdcf9014" + + "7550abcb0a722f257e01d38bad47cdd5a64eef43ef4e741bf50da275720a" + + "0aee47adfc5cd2534b911dc269197c3c396820b303f6941e3fd85b5ed21d" + + "6d8136745c3eeb9f36b1f226434e334dc94be8a5606079cb7643136aacd2" + + "da9c38b2eb7e2b898bd8632003767bf0c87d00a3c2fcee48bbbcdd949af3" + + "3455128216709df25879b0ce894ac4f121dfca6b8c7865002b828696641d" + + "14ffc59924fbda50866fded0afaea545c8008c564a3a0b023f519a9980ea" + + "d541d91d1c07a739fd02286ea5660e473f80494236a68e84ea31aad71348" + + "e45055ded69c39941e31d51df257a4d0b0d8f025dbedee093f2b91795bc1" + + "533dc472020769a157a187abd6d8d52e1693e2ef56b2212759d0c0120e54" + + "c425d0084fdb3925e296dd6cdd8e677043a90674904057d88ebdea5998aa" + + "03562a790adecc4399352df43e5179cf8c584d95ef8e4b37295946b1d37f" + + "faf4b3b7b98869184e42ea8b304fe1059f180ff83d14a0861ca7c0682c34" + + "b48a70df8653bd8d9a26f9489e1271fa44e41b392e648d0e619ecdad2c53" + + "952094802eeb70ade4ffe096e3049867de93a824217e31364b18204e9681" + + "dd8e84ae2678aad155b238f59dd9bf9ce07e97183a690b2a46a8f3624843" + + "5b2f713e7d8dcda4dea1e3c4cf9692dda082322c51f7bb1f63d92aa987ec" + + "cf1355a043e21a7b8d60a2b97f18487f6fff4c77df92dbfdc9837540c518" + + "9fd9585731bc6e726a34ca21154b0499522c9d1016953dd0fa2eb6a92b6d" + + "14d6e3da5c12fabe92bd639e253983fc91041091791643", + }, + { + key: "46e8eb27acfdc8f4be622d8741c7bc414464c149e21da97ab4afbf3e07b98b0e", + tag: "56b5f49be824c7a19b19faabf0787a87", + in: "ced52b76c057872a60107194b432cf04b7be05e65209045d2952ea0284d8" + + "3e2ed5a15cfdc58071204573c18ab03765b4d5e63a601419e039c42075b2" + + "7ebb2827de9c6233d6632e6d3db9140bdb4a9291d53f33734c2dc8e24df9" + + "0764dc10e0d321d20fdf659bfa2a81bc9e04fd0f83448143276647c08bfa" + + "dcfe3bc23898eda655c9353693ed7b022f43eefa23c21db7660c5029ca64" + + "a6085d93029ea6c43197356f56b7624d4819f5008d053357d981ffbe7f40" + + "96d6c55d8417002d36189b04bbb2c637339d90f4910a400833a8d422d88d" + + "c816c1636e8d9f7f926c244a28d9e0a956cec11e81d0fd81d4b2b5d4904a" + + "d1a5f55b5ec078dcb5c2bc1112bbfd5efc8c2577fe6d9872a985ee129e5b" + + "953e9cebf28cf23c6f9c6a5e09cb09ab586c6a50e4389cd3110777591d7f" + + "0608a3fd95b99f6ba03984fb0e13c6bbbde3668c59f2f2b69d7caadffa94" + + "6f67e725d56280e59e66dca025a18d4616e81abd9801835bd94485bb2025" + + "dee81fba440005b181ee81dc1d7796cbec92e4ec1c9016c8e8073cf281ce" + + "f749993f09a618a4671d58b476feffa454600f82955c591882715148a826" + + "586f68bb50059914dce1c1c85e5e3951647c9964ec9316005209a58baeb5" + + "2c6d01e6b4c275c0050a7e2bdc52133e433b050a700b556d4314e5c041d1" + + "93ee47f47adc971aed1b63259dd5cd4f95854a71a947eae3d3d12d0d7b52" + + "c6cd2fef2d2e892607a9681d73ac3236fad21ee30a4f857010bc95c00d5f" + + "6f0c6b3fe50cd6452be6eec4f5f01542dc2cb5e2db1f52224f11348fe2a0" + + "5d1e5885f1317f2d06ce2813dc4c723008e836a2ee95d0aac66855fe4c3b" + + "1b2e02ba0700be759b1ef1c2a3123ee4ccf9200d8d4de5e0d503f04c2053" + + "66393d1e91b648392ca28389d976aa618b4796acbfe8aa356ecdce1f7786" + + "bf09af226bb9402317b6fa319bbb9248d8ce00b1f49f066c69d4df93266b" + + "938342cd7fd4b07c320c2409ef72d8a57c21d0c6d6d493f7ca94d01b9852" + + "e4fca6a9291e9060154bc38af6c86932645f53914709fc90e11db56ec471" + + "6d600ee6452041248ea8244f79534f793bfc1f2020855d817cb4ca3c48ea" + + "7f6441ce9af9bda61936c226d810086c04a35e8654fdc30d4b35701adccc" + + "016d5895b2121ba4066e44d694f6371d97911786edb73dc3020ba186a01f" + + "ee3dd6036c0e205a8d05979bad228fd12c0fd2fded6c7f1e4c11354d266e" + + "d9c2f706269c43cd90504997d93a17b39b10dab0ff083ab3bd06540ce612" + + "d08f46ce75a16ef330525737410a0d98fb3d484968f9c12edcaf50103fdc" + + "c14128ea4ad6c30b56247eab28197fe617e5f88afa5cbe003c63d423647a" + + "d3042626fafd2084a0582ff1b1efdb5baa162662048019546234e2f6b6a1" + + "d8bb971114aae41df7795b4f3598f2af9e8921a9aadc7fab6c780aaa32a3" + + "84865a4ccb02351dbc55ec92a3152d1e66ec9d478be5dca17b4a131b4a0d" + + "3d4420fc6123fef80fd56ca266407d58a7880d6b7e5ce2b6bdc9a3721071" + + "7feec573d83c83a2e3f7d4023f2f68e785cde728fdbf5054060e4c89faa6" + + "1c9dd10524a08811d15c627b3b4ada549a3fa1d8dd77c005daaf2addeb10" + + "0abf694da8dd692f113965cd6366a5a7b0c17e1f2a320243e2c90b01418e" + + "22426d0401a2c8fd02cb3129a14fdfa6cbcaa1f1c2f17706e9ac374a3458" + + "777761e986ee4c358d26f8e420d33230d198fd86704e77298dd4c40c5205" + + "7566ac0cd92993b21937c3a3b4a8b89110a97cf38c781ad758bdc28f3565" + + "60cf3acbedfa8e05b396d226ef619746e8e4fa84c8e00a7f0e6d652808c8" + + "9c9b123d9bd802624cfa949eb68af85ca459b9aa85b81dbc0b630856cb9d" + + "7e18cdc96b3c069a006dd5b716e218a5ed1f580be3e3ccf0083017607902" + + "a7967a02d0a439e7c54b3b7ca4cc9d94a7754efba0bb5e192e8d1a6e7c79" + + "4aa59e410869b21009d9443204213f7bceb880ccf1f61edb6a67c395a361" + + "ff14144262b4d90c0e715dbefce92339ff704cc4065d56118624a7e429e4" + + "cadf0b9d2e7ffc4eb31c6078474a5265beba0774209c79bf81a930b302bd" + + "0f142534a6ae402da6d355a010d8c82dc379ea16d49b9d859a7de4db6e62" + + "40f6976ae0f47bc583b327df7ec88f5bd68f713b5d53796e72e28c29e843" + + "6c64cd411d335623ff4f5d167f3c7b8cba411e82f03714662425c8e1bc1e" + + "fbf435d28df541a914a55317de0ded8c744a1c3a6e047590244b207bcdcb" + + "f4bd1f9f81210deddd629192c58e6fd73e83812f084ef52f21c67bea98ee" + + "17554437d9642e2e", + }, + { + key: "b41210e5ef845bd5a8128455c4e67b533e3e2b19dffc1fb754caa528c234d6a0", + tag: "72c9534aec8c1d883eef899f04e1c65e", + in: "7eeca180bb20d99635e36b9208221b2b8ef073fbf5a57f5190e19cb86c49" + + "89b0e8150d22ec3aaf56f6ed9cb6720284d13a4b0a34cd3d7f7fc7089326" + + "6d1893fa4185269fb806677ff490aec8f889896fca50d6c80d295875b1d5" + + "4a779b6d49305360b31011b48537157d0f323ff4e865d46fba6bd23a06c1" + + "46878cf9404360d325432312ff08ce495edca63a3c93c44d79c050e3f1de" + + "4b6ca5fedbbd43dbdef9ceb26d440a59c7e0be3a8e461c4f15b6b1e1dc36" + + "a71fc723ad593fb903e83d0804ce497fc49bfc6b6a602b9dc6e9891010b1" + + "4ca066cb1c68044c1ad837c638076dd3708078509cba49fdc54922cdf5d7" + + "715fb43e9b5a5942cb8950eade143577bc9dcedde58d51deddc70075e452" + + "bbceab1e95b5d003eb96bea69687faa6d50d9c605769cb4287b5d9924dd6" + + "8881c699abaa6f93e41dac7639cdbbbd0259099a3ed096f482a1fa322b15" + + "ffc379812c74e09e95f1bd3706347eac421fe56895e738a47fcd3e118773" + + "c3a7e7e264cc7ff5a53a80e436df058265dab9756fdf6913786a47e98bbc" + + "411052d58ffec9ee948e28cbaadaae471c5d828eaf3b3c87d3bfd495477b" + + "403da54f1418a15ace0d4d0df68f6a8f2b0457b127d5eae1f45ae055afa1" + + "8f058d5dd7eea559de3ae9378ca53f7d6dc9a9465ea1f945295f16ee0404" + + "7fc9dd3deda8ee32631d7af70c20edc1e12c5f8abd2e78f43dbd4cd6407f" + + "038efab144a24ea8a090a7ba3e6499345a60106220c2959a388e1a73d070" + + "1d854bfaaa86165a5aee934b615ac7f45da7c43a1e8f74613917ed10dcd2" + + "27e4b070414412e77851db5bc053e5f502bb4e2b2645bca074c18643e814" + + "4caeccb58be49ea9a552913c0616382c899635eea79a166988c206b9aaa0" + + "977c7ced89c4c7aaeaa8fb89b38030c44530a97187fda592b088198b63a5" + + "2dfad59a0a4c1aadf812bdf1881924e8b51b8fd4dbca8e73b2986b3ab484" + + "171e9d0cbb08be40ae60de8818bd7f400191b42c7b3200c27643f06720a7" + + "e0a17441f34131629388ac43955b78c31ea6602a70dd665f872e7669e865" + + "f6f40e634e8772d747608cd3a570e1726eb1ddca64f08582b022bb026eda" + + "6a913dc83f174ce3c18b9fc0503d3ac74e2fe45691d6dfb4af8c86d752a1" + + "6d6664fab4de08afe8858392fcc35cb9ea82fc42c42d48c0c0556267ea0d" + + "cc19b10f05e0318c4488ffe704b5036908f5cb938eebd3163503acaa874f" + + "592d945448fbeb93a877a26a72306a36e181745ba300afdc30cb7986919f" + + "3dbdc5c47ef1fa052a9e4aeeda3955f61ce2f30a0593a81dbaffebac5a49" + + "e5a8d1308352701d1ca9e620a67a89abdf5f0f8b1a0acfde5819981d4b77" + + "58799c0fe41030b86754837712af821c315301aa8dd50d1387b9fb92ee63" + + "10777e08229edd54e5e86b086ac281bd321082ef46ce298a6211aaa3aa4f" + + "6e55b5a4641220ec94cca73087760da1b1ac3e0da3f438214e691aa184b0" + + "535950b715a64d11485940dcaa3f72e0aa521002b1443f5e7880e2a85b83" + + "40d32db0fc4c4702e10f0fa24a35da9307850e945f608ad34d6cfdf6f2b9" + + "ff4f6b8e9eb5a883546578e2ff3cc5787322e4384640f42dc5bd05f432d9" + + "610dcf7c06cdf34762dd2a5e805e24aee8cebb3b4db9e4d1471da995bba9" + + "a72cf59ea8a040671b1d8ce24a3dce4fc86d2df85c8ab5e1eb2b0567c186" + + "4fb464f48c3ca72c7df2749542ed4d4be51b63769012ce3d06356856b2a4" + + "24995a2429a156ad93bc79c705e7b163149ce53a42c34a19680dfe4fd0f7" + + "fce38c30dffe9da9bc941d131f435c1398f8284a230e9d6e3992710074c3" + + "881d03aa309a9edd0fde7a39c33f6455dfcc5ae3fa20ea0e0d6549a43536" + + "b4cd8a2991a135b7d7a4265fb840318813091274414108f13fe191db7774" + + "6a5f4270f6d51a29ff523954f84cb76131d4abee79161dcbd97dc1ef24cf" + + "db1fade057dddee00a1e0de0db1afaeed1b535f7bb402afa3b297551fd14" + + "8c8f3e05f1351d3a8ee2948daaf14e7fc448c4670c906ae076eac5a7c656" + + "fd5f9cd937b91e26c9e5adb43c138f8d65e447b0022a524e059f879c6e27" + + "4ff7e671f75717233aae70853d5bd7bbb41b43c47bb08d6dc2f54f9ec606" + + "9487d1267add72403d01552a3d138abab9ca8a0d2dc32439759aa5695f70" + + "1a17d28dfb85850fdb55fddadcdde4d220e4b05821e5736d346e7dc9c945" + + "72743366488b1de8975184771361894b6520e3407c5c2e38473430969e35" + + "b106024da8618665d58c9d084824a28991a33658d6ec702139e01b65b7d0" + + "cc537a644caeee880657803d95f5f67816948d5ab362922f8ffbd531473e" + + "b0ff8fde2afc37a4abfa28dbed0be1b3d4ed48a1d02358e8403905d33b12" + + "3066e7a9fe2491ee9eb24fc9de7dbd322c8ddbc5ebcd0d92cd102ebac96b" + + "90e2fd784fd6d4b699304df23b17d963080a013794322690456be525c071" + + "b78fcd2d1148026e44ff14c4d0f942cd44d2b3263f4a93b79ec7a618b4b0" + + "d77ae7a1f6e6c7c7e2f498b825bf1954df348bae45ae1d7c87b6787f1212" + + "60c9a724429a4a2491ef989f65acfdc72fa717486dcf1984905218e11cc3" + + "970a09d71061e6df751f100abfbf", + }, + { + key: "d9b0dc303188756312c12d08488c29f43a72e78714560fe476703c1d9d3e20c1", + tag: "6b9782f2a09b59653aa448348a49291b", + in: "dbde1820035997dc8a8ff3015b4e0674e7ce7bf0c2d994b7977f2d91b49b" + + "f200995040daeb1218a0f4307b6b8211913992b070d321bdb947b4ba5017" + + "a0885e7e5502710a75cbbcb56d49e1bdc2bc2afa5a0e83851162dec41340" + + "bafc41c5e11fcbf4ea2ac45bc57def4742281bbf734777f83c9ae1ea3d5e" + + "d42380230570f59c40d5dd9a2d89b75fa3c92664f12a274d965ed8de79a8" + + "b37f3763939ad21d1703ad794f617c8b32b20cc4dd7c1b7f969a65e1bafa" + + "f6c43f30c9eba256f10201910e2cc31a9b13a46ad29257024ef8f2ee29b2" + + "ee63cc5b6230ab9f87cd5cb534f4b0bb08a790466e0d57b849fffa1ed21b" + + "fb0b27804e3ff9df7bebf14e100cf91691a493e53870abfad6321f6711c5" + + "0fbcf1f0b2c1e5231d6c0a08e710525176355f6f82bedc1f787f0d3cb41f" + + "a11e91ebf9f4cbae46035a371232d63ef0d8bda0355af8cd0a2f7d1327d8" + + "0ab769ea0f1da0f76ec99cc737b5ce84675fa8a9ac0c98342bb82b5848bf" + + "656d35327ea01a1b09d84ab974c307511af68a30cd6978b529a8f58c68a5" + + "9d476062ace8897ec0d1a90d5d167e29ebaa6f46d93d697760c8771417ce" + + "94c0f3698985a98702833d1b68641b811840ca3d935386dbd4600fbc81c8" + + "728c4fd0e4588be739a048f03bd4ac651ceecd7e2fb120fe7190011f957f" + + "cbbfdc025f1ca0b356208db8cad87fcd53c5d3a30a7c2a48140ccd4cdb49" + + "f3961cef742caedd1e848bf3cacafb0da030416bf3177877aa0bc5f9d1cc" + + "41fafcb829d5e3ace9394028683d712552579e024084a6b855830ad9f567" + + "ff58f05d3ec263eddd6f56adec378f167e8dabbeaf7d0a9e65c71660314d" + + "6c8d54beeca2711113fbc32a2ff8c0daa8373278d10085d2a0660ad53f4e" + + "1ade74a483be180180acf9e9ad3ea5bdd9162ccd69599163a451c6837d5e" + + "a5e115bd9a560f395128ea002ee739009a44fa46078b18959933fb6e866f" + + "eb4612a56ce93b1affcb95fccaa18d71a148582ba1412a5daa07404fcb39" + + "c3cb4a2519cc506c1172c6c326016ae2e5410f6a438569f35a50d45cbf3c" + + "c46188651aa22c257858f60649cee8c05c75953ce49358dfe5980445fce9" + + "614ccd16d333ad236e29d204691ca0bf46f29da954bcaae52e41016556d2" + + "f4cae1d37565bcbe84de1b49f344d0200478a38187da29c155cc98184d9d" + + "33dca088d70054e0fce321f7a90c48a14963d0ace2b4e7a24b21c14a5e67" + + "1994fe1f7d22d1135d4df9268dd18d323fde3603288735626a5449582d35" + + "30e2c2225414e05a8c7b987c873a82e272a5d83e59b90f3d7264631d6ad0" + + "4a0cf3b5e96596a66ed5bfbc24ab6e4870aeec0acbad2cc5affaee06de32" + + "dca06f175bf763cf8e7fdf95941a177e934f0078be7dbaa4c9b6f5c16b4a" + + "5607bab5d56144a6ba3c7d9a084b8d1f4b24b6f9754ed207b230d3a2cc26" + + "259ccc725e1f8a44c4df8143e13edb5ebf073e2c9d2da5f1562df4feece2" + + "f6480987f093f642eb7afa3aa92dce2a8b60bb925cd2d11cf6c2ae7d2153" + + "1a9c8f068d71d0e682023932fe64e956a49347aed22b21084c4a84480491" + + "244ac6b337b6d12d5551ad5684766c68bacca62bdcafab6603c81bdbd8e6" + + "80d9d8b3825eaea4df023142e840f98ee251466a0422d810a54726a9f03a" + + "7e0afeb0043e60e2ba4908f951d2e87fcbc372096f2a9f4f2a95ad5faede" + + "3796b11ecf4401c3ee3d268bd8c46476c61e0ffc5c43c0f3c58c79e20f75" + + "520c102aa3c260972a870fc50f8841fa0553a9e30bf37ad282fb51b34adc" + + "7a933ca1691a8a706605ce0b906fdccbe954f8e5f2f63c42599a483c4be7" + + "3a041ef90ad930fe60e7e6d44bab29eebde5abb111e433447825c8a46ef7" + + "070d1f65862b30418efd93bfea9c2b601a994354a2ff1fc11c383e7bc555" + + "9e7546b8bf8d44358b1ce8cb63978dd194260e00a88a8fd17df06373aa80" + + "04a89172a6051bd5b8cea41bdaf3f23fc0612197f5573f3f72bce39c9f89" + + "faf3fb48d8ca918586d4feaea7e0f2a0d7a6afca096a081af462ea5318cc" + + "898a9cc09e8258a837559570cbd5eb901e8c0e04ee88ba31c81a76b000b8" + + "0e544feba576b3eb5272b53e46e96a0b35b9c759caadcec61444f8ec47c3" + + "45a1d2304e2708eeddfbfa75a98eab3493889047d690e84431d445407fdd" + + "99560c0bdd287e0944116f8ac62ab992ed3f1e2b415aea784b03c6904795" + + "f4326ff60bc839615f2894570dc9c27cf928ef192047528a1a19ec990978" + + "3b0d1a13dd4baf4a19e49bf798975abe2ad167dd574b32b3d0c22aa4d9b5" + + "2761e8f56cf2100fe5a39fceae3d865f3724d4f299d07ff899fed6baf7fc" + + "eb7189357bf56cf94a6493e61301b43e3ed158cb9c7a0e615fd9888c2db0" + + "7f7689762f62ef6b3ad4125e06b07a422f5040c3aa8b8f205d68356c9225" + + "56fc4c976165fed9599daeb297498ecf744bf6c7dc5e30604c461ad99402" + + "2eea0fb6fe33f82a97b5c272fd24162a94b761ec7e52173e7bb42e88b343" + + "64f5fa2c141ed04a86b8d00fd9c25bf77a8dc3e63f5543331405be6bf421" + + "6a891089b316aa4f887cb4aff0dfb4e80c2ccd65ddd9daa74b17b4411c0f" + + "c849dc748d9b138279dcd9ebfc6e6759a53f5c28a41bb82107d71cc161fa" + + "81291a8290", + }, + { + key: "fb70ae7ec12264ff9f51124da188e5b11dbf53cae2671363f6054b575b1ddcc1", + tag: "d9ab81fab28b3be96fa3331714e78c9a", + in: "c62edf20b1d53962b42386eb570b10378f9764421ecbd7c4802853332747" + + "19ff4c89c06005050fa9ba6579a844060eb7ece6c43bab520e683e0f36ba" + + "49cba259edc6ae35d41e0d7812a7d5edbe4d90cd5e0504d16f4c3f70d01f" + + "5a0313de55934b661ce1ec317968c2c4de60f45c66cded8c10565a1ca6d2" + + "3a84bf182df2fcb05956ed4d46b49fc0fe3bd23961d9466fde070341ce41" + + "bc6e148449360a31634fe10e91082d82def90d9da2c250ea72c58add2058" + + "d046b4392b78bc3af5b3936ed568733e8ad5672dabbfa3130a6a535ec73b" + + "da8e7223535f49f96cd35d56ed4792c5cb7076720d5461d96a2692b2ada5" + + "2be08fb7bad15d15a0108143790024f0f15f5adc275e783aa56b70844061" + + "e30952a040e4cb9650f2a010417812790105d8f58bd25d99b0db3cb16229" + + "3f6322e86cd5b0bb1505a7b998fb0f81d1e1915faca3c2c8ddea39115507" + + "80339430a7955521839deff5b301f3fad54edd5ebd2ac4ec9b1795cb4dc0" + + "e2eb62ebca8e886c3f1e507d10a0228c3027b472a7104b815f5ec8dae55e" + + "0783ff7ae9a3e6b99e381ad788206b135520cb870ba0cdbe876feea843b8" + + "5a82adc95a6d71c555f798da92b82daf0abfcdbc82ec30b1f12d78490b06" + + "7315735017a94ac150b44dfaace151896f873923310ffcd41e91bac04de6" + + "d70ea71565948c907ab21c4a23703fbbd2a8de6d3095f3d8f901538968e3" + + "60e7bfddb9d22036b1c23f4f5f1b2ee22623426a2d5de68c1e1a38e38e08" + + "e2b5670aac1edff69e9c73c2ca56cb69c709009ef1d541aff1fdb2b40c92" + + "9b87f162f394b76cdbba1f5605993e4dd9c312321d59b0aa5c6e33be1b10" + + "bfd00b92d4c02db064d0e4a98f2913c89051b0f0ead163deb5087b6466d9" + + "84f57553b0fa53850eaa142e072fd91802eb9f0d2eb7318dd620555e6ce1" + + "86706b866d41cf6ba81f100342faa14d801dc6f3d522db38fab17a879fcb" + + "b6acfe922163505bd23a6842f6ef6397ae5fb6e6016421998bd43b0142b0" + + "3ca3b16d6ccb7a47891c75c687d791a930b26aaa2e3412e7aa16e2cf1501" + + "7bf6df6d2e1c289af0d7ce03954a60c1dfcee5e4b3da51eb43ddd14faf59" + + "082005d0c8b104561f66c002ff426be60be769282fc5685cfd1968df1941" + + "73667e48e9ad681d35757f1199f1d93377bbad093c8cc3efa2bcb6ecb703" + + "694422772d15aaa58cab9e9ab277ed510f684114cc4a44ccadb3eb1c9a76" + + "d8619a9b7743106df6fb6f927ac49b22ae5bb9a9a4d231e340a2cd0e3282" + + "53f6d75df694826f60e4b3e758398793eaf73ef5d4b56cd1471e16400f40" + + "4a947e9737f4f874fe09a29ad799f4525156e3abbf0585c3c3c0a3744c86" + + "5d56db3d2ecba6bcbb1adcc8bf5f3b2a2d46d3eba18cda55201598a8112f" + + "d8f14e205f0e615f081b8ff6c5aa6669da776bfc7c34d5af4d0b26d0d819" + + "f6aacc53cf3c6653138b9a962acee9d6ea01d280c35bb1f05d1509238ccf" + + "004c5013167f804d1780d9f4ef9d45742fccac346b0472bde24ff5db9ae0" + + "16455a3c02256358fcd8e6a9aae94f8a37a1a3da58a889bbe3d295e16544" + + "2e580f59bdd31c92ffcab40c49c1cdbb4db1dd4882b66edc10fcb1704203" + + "c518c1d8d4c268588ce13fc38e0210aeb47d11d2603d4b3de5c6ff5e969b" + + "9d5904abb282b699bd04a6e9f1cb323679e30400d725aab128a032745dc0" + + "be05a46b02b34b93bff02523cd8498c021fc35a488f164a70ef1ceb873d9" + + "14a681d3a3a34cc76bfd5a547e2630d7741a284511bae5897d9f7a197fc2" + + "456af5c6cd7e1a93d3388c7a990b5feacd7749cf39fdecdc20adfdd540c6" + + "9d330195db7cc0d4555ea5f5356a3647e2265399f153c34ed1e217c5dafd" + + "c2c5dd3d566c332c7ddacb0d76ecd3a0ad505a4165443aa81b0f43cabfb4" + + "62942fe74a77c22b8f68a8b1a6d712d1e9b86e6a750005a3796ba1545396" + + "13170906d228dabf572ab969c762f8b296054f23d5d4a37bff64bf9cc46f" + + "43b491b41101256018376d487fe8097f1653a7a9e99e1ef2492600598fb0" + + "bbb7df8270be8b9106126d6f491f8b342a96ab95df6133e883d3db4c6a99" + + "402aeb58d371263a32dcf76d33c8904395b9cf0016fdfc15608eb43e20b0" + + "99cbe7455f7a76f69bba058ef96f83ae752587485657f89c7f26fde7fbeb" + + "a82ede581ee92821dc13b8202930aa58bd4f1c86f68926baca0d06fee642" + + "ea8c652d226af91a9638a0244f1a03c7ce56969b87cd5c1f86110d192e0b" + + "98dd979d74acca6c1956b1127d9a1f456053d17974081ed8ced0faa4293a" + + "319e5b25ba285c1151214f52c283e39c35af51c4572c8e395b7856697bfe" + + "dfc4145ab4ed0bdbe43ba509c06a196ae6bf30d7582550cb546c63b51833" + + "cb0dfff7196d83f6a1c6d6d712cce2ec1989fd9ff5a0a22ac5022b49d566" + + "58f196703e4809e7624fe7cfa6c13b378f5aac7e66e657ed7eaa942d1a00" + + "544a947199f24d736b8976ec2cfb563433c49ba131bd08b63636854219d4" + + "c45100c98e3092773ef492dd9210bfd8f54cfe2cddafcf5c05468d90e620" + + "0c2ef99d17fa6992cc45eff3072b7cfd51cabb07ea3019582c245b3ff758" + + "0302e88edc2c13fc43646ba34de37338568baa66ecff3accfebad88d143a" + + "fd1c3b09ae39c501e3f116af33b0b720d6c2baf5acd7f31220788b2f9017" + + "3ed7a51f400054e174d3b692273fcab263eb87bc38b1f486e707d399fe8d" + + "5a3f0a7ed4f5e443d477d1ab30bc0b312b7d85754cb886e9", + }, + { + key: "f7e7affceb80a0127d9ce2f27693f447be80efc695d2e3ee9ca37c3f1b4120f4", + tag: "41c32ced08a16bb35ac8c23868f58ac9", + in: "5a3607fb98eaea52e4d642e98aa35719bfce5b7d7902950995f4a87c3dc6" + + "ad6238aadc71b7884318c2b93cd24139eed13d68773f901307a90189e272" + + "6471e4bf9e786b2e4cf144764f33c3ac3e66521f845f6f0688f09eaa227f" + + "e71033b0f74295f6ddb91fe741323f2b54f420cb9b774d4291b06219f1fb" + + "4410b55900425c5e6fcabec76a5c2424d637a1641db6f0f6cad564a36a91" + + "0f49894bfd598e91f38ceea65e8253c1284f210cf7b50a96e664e562f3cc" + + "01c4fc490fa6d4679fd63fbb3ed8995a8a05166b573e92d22ef4370c6aac" + + "74ae94c94177e5f71143c6f340efceefda679ae76f6ed7f26eaa4848a8de" + + "8c40894316efbb06400f9695b18ba279e8947c032a84a40ca647d9ace457" + + "6dd0082494d6bd7be4e7928e749c78110af8774a5d43e9c9479964e2fddc" + + "ee51146460eac734311225d08c60706e40f298a7cb97f369ef599be097ac" + + "3bf1c275497bbd68968a235fdf8a61bc7cfeef0fe451bb04e662ca39f34e" + + "a8e3acdd0befe9762f9eeb275c0cdd43c80fc91131d1e0e790020975ab65" + + "afbea81f303ebd86760821efb4cad7cc01fd6d6fd194ac5ffe7703d890d0" + + "169e21b444cdbaf691fc741a5d99bd47357c37785755fa72582ca4754a03" + + "b4def86ded39aa6d9eb3f38801077e6d17e3cee3fb57ae83f30c79c3cf29" + + "0e2739c6b7323612cec3a561ebeadb4faa642f150323aaa9d270658c907c" + + "4c1610a5e1834730c08be3379cf1abc50c30e2bf01ce903927c27d85e135" + + "3db9e216dda8860c45925e2bb791abe5c8281ee6d16607bdca87f60662dc" + + "bd6e20224e7f009a86db66fadd8e37e0a59559328385090c6953cd20bb61" + + "f28a734fb056714f5159977f18e5c5f11de75f7a00ba807e47a29e4da32d" + + "5c67ec76ce4d7b669b5e6ee17e1df7c673dd8a7c87fce665cda8adb9547d" + + "1dccbdbe7be44846b4b121b0bfa65e4ed530789510d79bc4477e50178060" + + "f2668ac8956f39ef422ecb0e4cf90b8ce508552eedeeefa6c7d1bccc077e" + + "8088bd7e0e6aaf0bda9f11c412c270ee2ad6912f9808f9344a4bb137bdac" + + "b5b9372b00b0de026a8f5d1fb13972e1290b5005689f7636c43aee2fd443" + + "93d390371ae573f0e064b2d7df552b9adf04bf173d71c621795b9fb503dc" + + "5e918536c6ad25ce4a76f70e6b752b6d44be321187269a19bcf33ec899ca" + + "40e88b4eb23217095a85057bf95d8a54812cae4a7d32e0c2966a21376110" + + "74c6c8c3dd45a553c43c675d23308709f91be0b235d0222aa5e1e1ce08f9" + + "c6b45ceb5b47bcd7d7b2d4380bcdbd6eced452d93e6d8cbe18123277889c" + + "7f86b15fb991364a501fbf5d8244f2e3332ea0ab49e833c6f765017a4006" + + "cc7cd1a0365945a8d8873cb21832b210c83e451c01ac949de2fb0f7a420e" + + "405bf64eb251c6f022181595d68174b91e503187d3b3f49b60c23e44ea40" + + "ca20311305b413047bb22e89672758b74d6bd1a06decf09e9556421087a4" + + "0c1d2c44c5fb13d4d9625581ac4ccef1a1b5eeb5689aac5c0291aebda276" + + "50daf9d4396a64d02c6d58bcbd609d9a0017880ae0cbaf02ad0f1fc8d1b3" + + "ec987ffe13102d77352690c9b761bf13ea0b3a8ebad4a0823817fcaab4d0" + + "9b0bf03486620761dc77a6ba007ba07153b17425c4026597473e78863cbf" + + "430c0e5e9b04a83ad11506b61b8d9be3aeb06b5114e0d53d4724863eba12" + + "4f3b974bdb0d02743520409910621cd730c97ca984fe2921c38055f83ee8" + + "c4611db92e52d8ea51d89203e89df7586c574df15f3a96ed5a10bf04cb27" + + "f9656b5b11cf35fd21360b029ab26e9a741c6b3e6357aa1a41de2cac6e85" + + "f9a49e3441e60a60e74f434e1b8cd4454b11962e5507ebf904e9d6c52a7d" + + "9722300517c434758fbd6191f4550108b143eb16c0b60094fdc29327492c" + + "18a3f36737e506fda2ae48cd48691533f525acfffb619d356bf8347a8bbb" + + "4babdc2ac866e497f192e65a694d620687cfb4f631fbd6ae5d20ac2e3a12" + + "4d85f9391a240b616d829ac2adceedf8f3451ee77e4835639b13c622ef8c" + + "48a181fc7598eacb419fa438d4046aa971942c86b36eb8e16eab67105783" + + "d27fc56f5b66f35451b2a407d4648a87ae70807e45bccf14983b3abcb198" + + "d661d562dfcb00ffc569ca967171746e4e36f839946bc7d2ea9a0eda85b5" + + "a5594f6a9c1b179f7230eaa7797a6aaf8628d67fd538050cf47aa654778c" + + "11dbdc149458c1ec2233c7ca5cb172356424eb79479b6a3eed1deb9f3278" + + "5282a1034ba165032b0d30733912e7cd775cdb7e0f2616b05d521dc407a2" + + "ae7dfcf46fbae30547b56f14dbb0ead11b3666666c45d345cd5dbfa200ae" + + "24d5d0b747cdc29dfe7d9029a3e8c94d205c0b78b56d5e18613b3169bd44" + + "1b3c31513528fe102f9bac588c400f29c515d59bbcb0725a62c2e5bfb32b" + + "5cf291d737e67f923080f52d8a79f2324e45a3bd051bd51bac2816c501af" + + "873b27f253ef9b92ba4d7a422e2fb26a35c1e99eca605acc10d2a60369d0" + + "1f52bca5850299a522b3aa126f470675fa2ec84793a31e9ac0d11beab08e" + + "2c66d989a1e1b89db8d11439ad0d0e79617eafe0160e88384f936c15eb15" + + "ece4ff00e1ba80b0f9fb7a7d6138bdf0bf48d5d2ad494deae0ccf448c4bd" + + "60f0788d3f2b76de8ad1456f7572bd0ffd27bc2836d704d95e9c0df34571" + + "9dab267dd805577fafda03b834dd225ad9714d2bd182b4103faa5975180f" + + "90d5d6cac1825a19b9d4c87cc825512ae9dbeb33d2759c990905050f960c" + + "db3eb364c15b593524c882902b2a1d7fe40ea3f54fb0202fd8821463c7e3" + + "4b02a1209ba0048a9805f0468a13e03d18009318ecd92042959be263a51a" + + "407f1e660632c4247419659a4e073a8e9cd4a226763a7daea464d5427270" + + "7efd053cb4efc0504602c4f63e7d247b55db2ce1c07138f585d16cec97a3" + + "0731d5aec2166cb4de41695feb76280cbae1af8a2e67c2d5a3ac5487ffe8" + + "640f308ace6137e83576b79d586b663122221c20aba7a6bf60f73958f436" + + "59f087f850ba6e2d7fd862249c5fa6b20e3e43d4f2aa10d4c9cebfcbdf02" + + "6b8d103e4f89b93dd8af172f421001c8b162bd6d0b847a58ac108b6d6cc4" + + "9c7a9ba069deee", + }, + { + key: "e3d21f9674f72ae65661aebe726a8a6496dd3cc4b3319f797e75ccbc98125caa", + tag: "3c95668130de728d24f7bca0c91588bc", + in: "baaea2b4b4cbe9dbc4fa193c376271f40a9e216836dc35ac8012476e9abd" + + "43dac6b9ce67dc6815904e6c84a5730cea0f9b4c6900a04ae2f7344fd846" + + "58a99513ffb268c6899dfe98d605c11e7dc77de77b0d30986f3051754503" + + "7c26be7b719aa9ca1140cfdf4c586b7fe726a8bc403249396a11cfee0a6a" + + "f6c5e72259785cfd13c2897384fe527100170001ea19106aed38f7d5d9a7" + + "ad43f0b41451e19989192a46b4f9734a774b6304cb74feb7d83822044a24" + + "2e51d55c0b8318e0439493bd1a57cc13f6079166cabc46877d003dcd39b2" + + "c0b90f6b32fc77acf04a6c125e11b35d91e2b18401cd53df4aff804e3c67" + + "a8bb3894b27c6e9b0070b53a85aafab0c0a253f9cfd4d3cd3be52428385b" + + "24a3f9f71660ca2c38474d14a0309e2f400e2c21af6e379099283ff241d7" + + "51da5a96a8dcbfdc43b913b29cc8cf8020eebb4a67f5bed31f2e383f8656" + + "8c815ff172382b425e95902e80f5fc219eccb51b656d37b56660f749e5b1" + + "4976a23648680a472d02ba71476e0afb29a0e084984f4eac3befbf8dd802" + + "2b7dca4dadd18bbe58e49c49ce48a06a71557a9a620c51e2623f818e4d62" + + "c2564c7ba04595cc109685869b183faeff2ac7a65049fc57cb10fb01951e" + + "a525332782d691f9759ec2ecd68bebb9c7aece5d522a08ce7830be520db4" + + "c9d60a2e490eaa0c91e37b256a97f84b39fe3c77953748c3b86fd84e9547" + + "a298c049cb28b8c85d59548b8dce635d59487c9de615802d16a8adc4c0e7" + + "80f35b9f10588a431b39b499dca929ab9d225f26e5721820627fe62427fe" + + "06d5773a50878b6effe840dc55bd3ea0c35168f6b6a972d57e8f88c5993d" + + "1ae33e0b7e9459c123753b518c184de7aaf429df078c9a18a29af77c727b" + + "796f5c1a501fa8105ee873c4e78c907142eb19690638a182fddb413adb06" + + "d66db19c7f6f46dac582bd72a6347b4427a576eb769d233febaf7be8f768" + + "337273c12253924f15653f9f3602b783703a81454a1dd7a8772a9ab1eeb8" + + "51be33e0c6c0708f3cc2012cabe8e2f0c38e35372abe27bc148fc4e1054d" + + "9d151f80aec0232a3a92dd77928a3678ebd7d09ba7b4e1d83227257292c0" + + "b8bc4a76de36bff6c9deb383029afaf4f37d5b935dc080a18665545e4acc" + + "195da0b9545d8902408886204b64f8548b32d012e0cdc520c17d9fb3be97" + + "800c2e2b945cb09a75a0a49e5d4d81c4194d91e839333b2b9b9e34d588e4" + + "e20cc1e911ca0a1429fa70ff063f0090fd842f89dfc5cc44affcce4e1e1b" + + "8b11c612f66b074c03ac2a055fd8f51ac9ed4f2e624589ff5730721d077a" + + "fb4c19e43abf8cf3ffa698362be8be51e92c2c91a4a56be64d9ac6d3fbaf" + + "5536a24c7fd0adaf74ca84c508e5e8c8bf7d4254e0c44158bd26acdf3f64" + + "e78438b3aaff89ac9986cef1e3a88d5bf2016340367a1cacd01ec167ec6d" + + "185d93a2a220d718b43ce1d429d2cb598605660b030e51e8d75fdbdd5b8f" + + "8677675e196a40a88285b18b24c5d2d594bab3d457e6f9e503e38cd470a6" + + "9ff8037c9a0a0f110a434335d954fa856a3721e0edcfb14287c3dd9639ba" + + "4db32b7da0670dd0a872e468e3819741d0d4ecf0a4f7a011bbae1493c01e" + + "642757491189f8664be3ec6437c4f3c76abfb0276e44a4d28871d3487c2c" + + "ce2f230452cb06184bb8620919659a7ba0a3d5c12ec25678b03403715ee4" + + "acb6a53d281036d8f3a085143cf5ecc3a0c6c92129caa7ac1f645c7bb95e" + + "4f63da38dc319e2ccff4a9006f9b9b1a38c4c39f6dc686bb82d43fb9fce4" + + "0c767d3ff22f52c5f9900130c65bb6a9cc7408a777d49b70946665f4a733" + + "5099376b276a43dc9a6382bb2d40425f6481b1846148434c672b84dd7a20" + + "33deb5140d43ba39e04ffe83659b6deb48629e1abf51e68748deffb756a3" + + "ed9e0807506b248a024cd509f539f4161366547c62c72933584e851599b6" + + "82ec16f1d79e9c6a01cff6f51ba7f46b67cdca09f3ab8496322b990a6116" + + "8d7574854a1cb1cb8f30a303dbd13a095df56dbb940dd16ce79879cd2d73" + + "80a419842fa1b34da668286de4c1ff5917b7aaa64713c349dc8f855d04ae" + + "de9a3a4d0739dfc36510b1e7bb1695418164285c44631b4b1a7c5798ecb2" + + "d976c1a3679a827bf0e8c662567e402bcc1354222036ad5959a6f0b8508c" + + "6a8c7d4a63e7dde154d778fc80a011592771d55801c7e1297b00b77f80d6" + + "314ebd1f5b3057398d1943599897cfabb65e7568d8fbdfcbecfd4b8a83ca" + + "0a7bed08ab9a656424831e0d7718c15727af7c83b2ef5eb5684aa044eca2" + + "ba896811246766248b20a325094a4b4159f9cde1ee349be6dc3c9a190453" + + "0349212a9537f65ae333c288753cd2bef6c5beb2f4164168d965a2c0fb9c" + + "c8c73d9e776e23d53ddcfb83bb7dfe2a1b8c781280f449d6f310faf8b53e" + + "89e6a611d6d3f42f2aaed5259730d149b3e7dabdc9f865bc1555374738c8" + + "456abe112e9628fb31efc2ecdc972da05987aafce728ccaed246cfcdf518" + + "3fe5dae528bbfb99d33194167e0f84d462d3d0da83e92227cf57922c7956" + + "4fe44648d87c69ad708e797972c44c4a5183fd5d1150a1182e3d39c3cd16" + + "3920f1d7ed83992bc4116d9351ae1c6c4827d1374242e374310409f32d5f" + + "0f38c78b6489c568b791c70394d29ea2516dcb10e51bdad862ce3339d5e6" + + "14fe14f150961809c36e0a2c8eb872e9f7a1c0956fbc9194cb63ff9993e5" + + "d0dcf62c0f49e81dbe99f3656c4dea57b766ae9a11254f9970618f1b33c8" + + "f339f440de240170f7a21f03ff2da42102b323ce2b9b7d0de5aae324d1ba" + + "c87b1e4c5279a566bf659778f8b03882aded57377a0f1b063af2897060e4" + + "23be7cefd4aa9a28479c16773944d254fc21d3e1acdf508b7972372b5991" + + "3b8b088e93471a7d54c6ae4c52ba465ef07f19f269677fc2f64d3fb3d7f1" + + "9069d6c7001d4b002ed6683c59bd5651a450503b68a4a00820b8c17e3263" + + "18f32c21dfbcb2a02a104edaeff67ec09533aaf3d1a7fb41aa5d506ccdbb" + + "e6e35fa0a263c0aad3acc91182addf8c5bdfbd0626702694b8d652a63c65" + + "8d6b2b7c75d015630de508195e1fca9573b61bc549ca017c4bd888194d44" + + "3e031f36170215a301f922736a819f3ffda69117170d1933300366c5f2ae" + + "1052446ef7c3b82c5868be158a881597132f51c91c80c24ebf621393dc45" + + "05fe057364a76ae67494a8a5f67acb551cfe89f447df272ed9c1509fc330" + + "2c3e16541452d4d68438f26858724012ad3b72c094b9f166c6bedb8336a3" + + "41e032988f39cf53535789b320b5424d07b6bf5f8792e3aceb0e868765b8" + + "611d7905089949e0c273e2410c72a146cd63981f420405bd883e5390e985" + + "8214a8db714e8400a21d0636d7e5d9671a3582ab9ff032170b8dd6b9d5a2" + + "144d065228fa54aea9a22654df67f3f62c5fc59d68914d8b219829b536cd" + + "2ae937ecccdb6031d94cb3", + }, + { + key: "84373472e362a356bd5c9b50f55c588d067b939009944f02564f136c62dac36b", + tag: "12dd5297cfcec53deae1dd5f9325d894", + in: "860d9b2954c3daf18fd67eb8bd9e6e3de2e4988ad9b04b1987219204dee2" + + "388db1c59a935de27bce29e7cd3ebdf038785efb35eabd4c3785a62b1d9c" + + "3ffa25e2273cfe5eb10b4ec6152cd8f21dea415421b452efc7cc4ea6bf1a" + + "b85fa6614e7f6d650125424865386ff8ab53247a63ff023b2d0753a9e5bd" + + "458d6ab0156fd3cf2d5002f902f927a847e8c4a8426b0a5191f5e237d590" + + "2659ce9be9024750d1d618a6b8dd57efb6c2bbac2930858f1132639391aa" + + "9e8a620a2a7d64bb7e943c77753401b5b619d95ef857df25a52b4eb97372" + + "a05416706b2644e2687bf1d42c0cf06e5eef8a1fc7e178440bfebb85c44a" + + "4837f69e43a1789728a999c5e04291576e757510f22bca11583a4e93688b" + + "442f2b2dab8d5ea9441ff09b8287862ca538ad979297cc75510a3d9ef36a" + + "662b4b7c373f184202befa5bf3f315642e6210763d033b7e2c59731cb356" + + "045e9470bf2f83cd62f11b3e904b0c0b1be99bcb805150ba7ef12b8df3ca" + + "bfc5055640687d710ab88e0fa8034b26112ebfd044a4b290b1c6f6d18c31" + + "ba9880b1cf2d81b5d02f00d6d351da5dbf47b6a5cb7b53eaf6de52c8a68d" + + "053602ccffa37ccb44a7683ab4f8a58c4bbc9e140e4e6f3cc10a5c07ebd6" + + "070818db983f9f415168606011efab6b8d7b4e61e8eadd8bfd8d028b89bf" + + "b0a16996252d7b4ee4f9ab50fc9d6e482ecf99beeabc38d70efbb9a0d4b7" + + "9a1c5d2835adf8e25111352eabd24d562644efc97637f695e4792f2049c6" + + "00f4d889ceb951cfe289adf159865d013046985d7fe2598014bf2dbbc528" + + "b4166fc2180e724ded8e7ea1c8d66338ec50d955d5594a0a7b4655338b70" + + "e8978485a722df814fdc6fd2436dbc060121fcb575672b2a5e454c1209bc" + + "2bb21a99d39dcb3c697306dbc2104d60fd8051c43ea2fce268987d0ec249" + + "a5c02f91d3b0dfee181b3cf8ef1ba9665daf7ea1f1d3b216e378943b78b6" + + "bb41e5dba095748bc776f8df6383033a1f5504955da3f42153b1c7ea83e2" + + "f90b990ea0c5bd3906b5c4060b19f447ec7762916b8766e5a23bc4d39cdf" + + "8e27752df8129b60ccee1731e47383b589d4fcad865eed4041a186df206e" + + "9fb69ab6ea092e36f186a6fea8d77bd7f3ab0fa0e29404d617317c75c832" + + "854427848237cfc18486c95f7213b9d53f324da036e8d298133b5003984a" + + "b9d71836f9f1b059db90005a9067c261bd85aaeed4d623df2220eb52b73d" + + "d683abcdee5cebd411996f853752f638bd28df6d78bec2ed3e00d7beea06" + + "2b81c19682ffb2f6abe3a3623a2e0570650c1384f1818d76fbefe3a7ef3f" + + "46138160ef897f9934e00e066e215230e719c23905dc60d7fa4d666fa52f" + + "e7737db15126d3262c3a4c385cdb23ff3b56c131e43b241f4a6062a1a248" + + "de9f13eb82c11f7b6a22c28904a1eb6513cdb11179067b13c7b5f83a58c1" + + "4f2753f19fdb356f124f52923249d6e4a2c8dadc8bb0fc91e360155a14c5" + + "c194334b9f0a566d51fad98592b59c1cc4b40eeddb34e64f337f83874884" + + "0583f853398c343dabc29b9444be1e316309fb8d81304d654b3d4bc4cff3" + + "55fc31278fe22e649324ef10acd247c0b72397edf96a1c16bbbef0640296" + + "4d219575fd23c36efc1fb8f8a34b510ba9bdfb3b478e236777ef7c6c47f5" + + "5a2bd0383d8eed3759456ffcffb15e61985b08c022658a5ffc875821bdf8" + + "83f69f096dcc72a96888c3af76db57a54be701759670bf05cc9015f5bf1a" + + "745cf755a25b1403a870875701427f820c4b29eccc260f30113629ba03e2" + + "785014bdcbf34d0c67aa6aca20d2dece811788686d5a45820d2980bf7d69" + + "d5c820a09bad7bd95166f63dcfbe8652565c285e60e2704955d69b3037d8" + + "7f5e6567d95b8891276d5cf7c59047d10a02ae4a28794405e2524ec2d595" + + "1b36ad1b9d5265fa098a033b88aa66cd9eaf01eea49c7dc4cc51c486f624" + + "507a2be23f152f43709b2cfecee44945ca506950e90e70164b77e12e1c13" + + "0b4d1021c2afa20038f190096276cd22e89b6e7dd10fd58fa033c9d42536" + + "98de3f4908203be8dbf259112f840c76726d982b4a837cae7139e27182b6" + + "1b4dfbcc50e42d5ab8532edfbd30f668879824e9ebc34b63ff1526cda81a" + + "e38352a774d79f73219500e57f0159a32326195d8895d965071834876a45" + + "c1a3c0bc4b1638535f7d40011cd5b23343fc27fa318c1aa3f9d8c43351c6" + + "6148dc2175e0e620813266da3000954dfa22048f305244629d512e852376" + + "6248a897a3ec3e2983aaa8a0f025f18feea57a5153a59b02604ebfcc7a9f" + + "b03e62443df88ead9dee955e23bcf6528c278a353f254c9484a67a7b263d" + + "a301923a4efb6866aeaaafd428e6da48781365bc49e90cd16b2388220d08" + + "bb9f79d14012b5a8299a651917b6a829488753b6ca449a14e8dd8c5fd5ef" + + "657d627b8e7773475b802655dc033694f24376e3b01e519d1aa8365d0e55" + + "92d0a4adbf555639b6d75d7ee59a7d12c6c11317b7927f11bbe75ed90508" + + "b0698420e231206704d22dd1f1740edbdcaf19a47d66ace4eecbcefb77b0" + + "85cfcfaced4d2d6048ce76434eb79990f0898adb4af2c377b581ebab3f3a" + + "150f40dcae002d4caa60050591c0de4ba83bfd59a08670beaa4641aa9829" + + "bdbb720d6eb8b2f3e864a98676a67271a82cffdca2b3590a0b5f97efa5d4" + + "ba062b4798707159782bedc75e5363d5f5d55ec2bef70db22955adf401fa" + + "c3b7af937816eb25d54d9f2a92e5a2a04bd8b8d7568204fd289f5ed2e033" + + "a76209d288e11e8a4dbb06b9029e90cb186446746853f02d738e06bba538" + + "894e03e2658ab3d7f9ac861d2cffdf12396004d1cd15f18812d3803ab9e0" + + "6f41c9b374d6a0678bb82ce06d9e3b9dbc8d2e90b8f64d0d040f3fa8a3fa" + + "8be71d2b3183cceae1bcbfa2353689d842f7d7052e5699dcc70ab2b58761" + + "7041e5aa1e2f41911d525505f061d3ca45152f5a7a1fab50c674e4597a52" + + "b46aafb4ba57413879cad1308321843abb7c39696fc2f2e225878bb1191e" + + "e151cc76f1a1b8d491c1672fecbf710db82dcd32554361967fc839c8e5d4" + + "e488856e1b9382eb3fc3bdc3b6886a3cd79761b02bafa080a745ef6afa26" + + "822f1d10d5e8eefb842837d82c9986e78fc3390caa142b7643de8f613e5a" + + "890a57f5883409549537f8139534f4ca1b60f33e42be25433f1d82add530" + + "6a4cfce258c0d4f1f3c9148ffb5c4b626d51f78ac20bff0393b7fdb4b9cd" + + "70fee7f69892c8a9ee089c6c5c7bee0a1b825e5b9517f2c82d6c149735fe" + + "45a8839812c2deb2a355b6230697053092eca450b7b0d3242b2689efe364" + + "09e820d91fa4932034d96495d9dd3baa4b385da815a7cb69438ff648b326" + + "e7efe8d688e88570ba59df7c439faf72c95317a10c984c5ec0043407e9fc" + + "9b46487810eac19d2bb40e0a654935f76e7d8861480c5f48419eb33084d4" + + "0e1070e5ad542c94f58b49e67dd05b6637a2c67d41451b7e00ba30eff221" + + "755d6d427ec634a2b95980d274a89579feccf1c7df3787a9435e588f2496" + + "06a93b7ac41c8aaa84b91c95cad9463d4881de7353d95b13bbde4c9da90b" + + "f1fe96257309a416407c64368b5564f022c4a493f2a39df1696f45801e42" + + "a5", + }, + { + key: "2d0035a30d19b9cbc7a27561f3ab474c01115c4499b4adec660ea06ebaa1a14c", + tag: "a2c77b55cb0c076d8ea83cfe0e64f293", + in: "4e667580ba4f38f64e5cb5566bffb486dcae10cd17acb3754251e837767f" + + "16429bba2b832f29ba538f97f3556548d163be25e69f88fff0743150623b" + + "e0a1d82af9384ca335927a0e9cacc3dadbdf1e24fa5c81f2602d109e1400" + + "33929e409b9a0fa4f2653944edcb8b3ef963ba7f8806196c73bff0ded670" + + "c6def5d240c5f3daa121f8d5bec9b2a0b0f1d62d54b013dc742d6bd46325" + + "460f692b76d4991f0796820ddebf150c7d33829795784dd2759b334d2706" + + "70a7264941be5d99d460d078a9eedc3660cb3176ad302f9365f0bd698e46" + + "9f3e63511abc81109995dba17be1abe8bcd28407c7fc8d02c14794bb033e" + + "178a94f6dc73719d5bc235f980a16eccb4121ca83b13c4e165931ae4f192" + + "4292f8cfdf1c3ed40feb71e13d919b48fa296dddb4d23114a3d86ec10f16" + + "f314de4cef813ed24b49f4c7bc44cb8424df1f70e8d77366161c7cdd709e" + + "97610aca3a24fb2202ffe15eaaa25d711cb5179212a2c6497a13e5d7c365" + + "7bc502b3d2ebde2e57b714dd9bc21e73795f3d35d620613918c4c9aa0e89" + + "031481c97a5a4c15ec6abe42d40498c33d71c823bf1d5bb5fee457e2fff0" + + "bf777c80c6e3336ab3ce793440e74b336a8f7034f6ea2e4ff5ea4ea7c350" + + "65cf2ccd2da1d6df29bde10f4cc0202b5e4cf7ed097da49b970a6db41e5e" + + "98f3845b42f46663b1d1ff01da71389a8737ba8f51eac1ef357ba5ac9a80" + + "dd2c7f9476111dcd651fc33f4c86dc8658656f3f02a8878bc38ff0d0a1af" + + "2e31fb92eaef08c50195490818661feaf90e8b6f5daa1ebedb2cdbc8d5dc" + + "16db3505f9611ac46bc37931e02c1fd6aad6e4b7e187d5e6f990fddc9563" + + "2b33f55bf68b0db3890b11113ecc839a4fa4de25160e574289aabe4d8fb7" + + "9cecf9d2fa75ac8d0195beefbdfe0815f8d7d9751c1280a29b547149ec7c" + + "2295f5afa53cfb516158086bf203357eec2a5db71143f996c81555a47f92" + + "209719a71570a5553f1ff9b4b41827dd74657b463f36623565f0c9f4d2ee" + + "8735d6af56ceb3b3d0ec516b22f0ddafbc24647481f61ab169e2616c91c0" + + "e1f6a35436598ed801670e1dba76226cbd0544959ebe70f836c8a7df575c" + + "b907d780ed5aa0d6e4e8e0d2f457efe89a777374aa49d4961db96dbb787f" + + "021d99231001360d532a70ee1fb94bd6f26524dd4b7556c6d40e08723d7f" + + "9905aca66c4743f2bf8b34493bdabcfca617809a867bfe0a4f94c756a6a3" + + "dcd04ffc0a3ac671a0afefe0d5d447efcec48c6368998760db6a572676d4" + + "29b6d3d6e0c815650447748c4b27541c5447acfb8f7261b6378f3fc0fdd7" + + "375eb9d458648c7fe9cd96344f11aca912cc5098e9ee39e0b6794cc1dc2d" + + "f1b10f927102705efa20e667b63a91f935c17764650b287f5289d5790766" + + "555f31985c5aad94c652ba41fa9c0195d15405f1fcce9e23054a42c8a252" + + "da83bf6268782ba44edec5d8f94a20b1830cd1c5894cc6b9b52ad0b12a5e" + + "cf3195a32a0b02483ae3b954ac6f3af1e0f334221279d03a72138f3a2cb2" + + "1e706427c4d604674dab88d429f28a67be7a996126e077a1dcf8989d90d0" + + "8b08f4abb9a546b3c64ecaa287bf3468c59add86365b885f52afe13ed8d2" + + "69ea61832a7ecbb96ff3336f58a1eeaa6dde3611f3ff7c2cc8c9b745b0e8" + + "b5919914245a49ac192cd77d10deb9a249623f696065a532c20eef9e9b0f" + + "e706579566a9eeb14d4e8251a7750e29eaa60f034c1a7a1d51aa03a45fff" + + "89acf41080deec5506128b06f003fa46bc4021a82fad6a8052a49744ed69" + + "45bd9331b5ae80d873cd042bff079b2b9d8af8065a22c449c32a56dbbe7a" + + "80d0f3e30b9167532506915883dce0aa9cb749e4368c595c5bd33b57e36d" + + "98cc9bf91cbfa47331d69b5cbe9c92bc66c0fc9ca8717bfc108e1f710333" + + "14dba02a28b9aa05890cb01ae9175806c3c4215bd446f6cc96ec5d08982b" + + "4f83cd1646160e1d306b3cdec02d251f0901b03e8c3c35464eaa5082586b" + + "b55482db97599d513ed8d7a82e32fae302684b7ede058474c1fac7893444" + + "16fec93fb982accd162dd956ba2f31a894e9366eca00e6e997fbbf9a2980" + + "8b83a139f6432147a717381bb8baa2205715f735c1e0db273cdda6897c9f" + + "39bf0d7eb7caf93f657ef4d3fecea28baf69cf36d3cf347081df3114455e" + + "b4fe3e49ad3c3f14435e0b39b6c0d16db0fbcfd7ba8da8760d5952c03667" + + "251e7a4c3008cfb0904225e55c23b884bb09d26631650460c4240bd5a165" + + "b531ee76ba5749b3bc60adad35de519321c1672b47bc35fb59f7792a3495" + + "11b2bb3504ba4a28717823a27a1f99ce6970290b26efcf1e7a0399b10eb1" + + "0c1299c09b80f4520d00e7908d004d5b6a72a411759cfa9523f6b2912234" + + "481b1d8fe4c2365961c0528bd593d42bebb398b5836ae6ca013fe440adbb" + + "0090e8ea274f4d8bcae483e3663051a328f7c12870b40e4973a9797a2336" + + "3d3c53e1b0d1a9159bfb26158f44734b3c34b571be641bba2db937d4ae1e" + + "edc807b95b1c2a7d44804885536316ad38aedf0d83b1519661f2bb5283cb" + + "9c50dd61c3753433e988189f26962d1f4befd444257d0b6d5b819d5fd572" + + "22c9fdff032e07a4d8686d451e71de4748965309c0a2d7c422ab7cf3d96a" + + "8c0a1b0afb229debd1c9421cb828b9f2be96bb9d6b5be7ef8134bd9ccf81" + + "51620937d720d83dbdddbfaba8ecd2eab6f1974090efde0ca963e9fdd691" + + "ed0cc5e074c5780779222552fa46ddcd951763a32aa3a044ff4a73cbab41" + + "dabb3c2c03fcda68303477f0dc26f35bdb5c9bde721fba1a2db732a89629" + + "a8de3cfebc3918df1a9d5053d09da5b7316e3285bf62156ca28cb64d343e" + + "72445fd66757bf4ab374fe7932a65f3d7fb6e42cb12e5b67ddf8530383a4" + + "6c1ee7ec8883e454a467df1aa7e468a6e7035515f473901efca5d46ff358" + + "70e0cc2575bbd7f8866c8e73cb157903a1694ff3051424f28de826984dcd" + + "065dc3658df144ae3a6d37b88c367e3cf7c58169dfdedda4a2821ce22188" + + "40472ff72f0dd1a6b0100555ff188b80f835259a634405e3dad61fc299f9" + + "307e27503b2cb7714bf3b636cc64b61d2e374119c8ef8adb21f1516c7fe2" + + "38c807818065bf312003c12e02525d69d9629a99e4ac66ad2e792f302cd2" + + "a6f5f702dd28040738a084a7052f2c3ed0924c33b7a5d357b7c9a29cebd8" + + "621a4bfb7bb34676ff210d59f7f9d4eafb7c5c490c9ea48402af5bb072c4" + + "731bdebcbed4e8e08a67931b6d7342d4ef7bc4a75ca1dfbd32ed6027d8fc" + + "b71e3f55565c02e06daa8c579b69774889181291c470576a99e11f2c5acf" + + "77e091ef65ed243d4287176f7f6ac7aba6908c9ff1fa43b894a499b642ad" + + "c01b2fa1c4b58801411941bb448f1f7a04794d2cfe5db1be61f7b86d6eca" + + "c547ee51d4c9050f9e9f318dae958c150acc21c878f0c7df6065294eb1d9" + + "a278c920838a0db752b080a32e67ac312fa76b589a385f31847196076ed8" + + "1021fcc375bfcc8e1361878e2693860eb21ff0595e4eaaf7897f2b79367f" + + "7c4f711279bf0c93a97dcb1cd8d87e444ad5f4cb5c1de44e37868c6743f1" + + "cd72cec376726f26c8bd4836f9a9f9c68042f95ca6f9d7cde493e531c553" + + "8bf7ace6dd768db69ac7b41ce93e8ca27ff20a83ff2148ec5b89e05d8b8f" + + "5d78d0fe16b96f6eb8d3b20126a186085c6825df81aa16b3dbf57eabc360" + + "71299ccdda60e250c652408d9cd1da94d73c728440ae08fddb901aec0fac" + + "1050a778b10f94f84883bee158bc53b1c001807c43a3151fbf581b18dda2" + + "527430872834e5c380575c54b7aa50f817cf3249fb943d46933cad32092e" + + "bfc575bd31cc744b7405580a5f2eabe27a02eec31e0d7306750adbbb9f08" + + "c78cb2d4c738b2274c7310cbf8dd0e59138b6a91b8253ae9512fe3d7367e" + + "a965ac44d54a7ed664e5e5c3c6c2d942eac388cd32beffb38f", + }, + { + key: "2f29d71d73f7af98f96b34e939e1a21e2789ec6271b878bbebd14d7942d30080", + tag: "ec02f4953a9a63ab6f2bfc3501e4fab8", + in: "0e0950987f3508239063e26a13727fefcdfd2cea6a903615c64bf12d9ed3" + + "887f9b2cf7ccaa196ccc7756b09471475b9daefd4261e69abd23b9faf9c5" + + "1fd5d5788bb39d3c068fa6807d30f6201d3f6dfd31715d08b1733440cde1" + + "049608d23c4e45c5ed61f863350232f85827e7c292dc5f1eced1cbc912e3" + + "f5c420bd945911d3881ede5153d3b2cc85371fff98d2caf97cad6ef59001" + + "4017f9690cab08989851c2647e77e81401714a93ed9f938b79f8f54e3133" + + "fc2cdef259df2ba0d48f37bf9e43792e3a777214cf4aab6dde6deeb543a8" + + "813b71b5974136c1220d6218a252881f0f5677ff5b6aba127f19a5f3c5aa" + + "c988543d7839a90a3f947c4e4d5c6ae1ab48dbd40456d1aa65339a4c15eb" + + "520e8ff9f965ac4c37735937cf09942e7958f8a6cddee41707423f715903" + + "ffe0d15af8c3140d3a736d23be7485fceb9f07c6509f2c506eda4ec9d30c" + + "cc133708f48d8828e332808c84a745d337296d871b9794de1c5d06534aaf" + + "65587526a84e2521f8b332645e0e72564bb308ecf99b7bc69608474389d1" + + "686ffab8c49b7f04dadc28d2ecdd0f508dad2135843304e378b3bc7a4f25" + + "7fa4316be956e0a021edb8045f39fa9f002087f067199bd6001acaadd261" + + "4bf6aefd3f098f92a959685f24bb2206c347359d9c6adc6847117bb434ac" + + "6c40ec618f6ae8b75a5e2e4d44c332b7b06c8b4d521493b9b0bde8894209" + + "717a24b320214297b62dec741cea018ea681c9b56702068528b3726953e8" + + "c5e4ccd5029e4183e772d9834a56a88d45bf87603dfda40e03f7e894766a" + + "7623ab4dcc0dfc3086d17566945069173935916f772e2a5f8e1547348f28" + + "782400fc069ac0e2b94242e9e0f1ba2d0e76898f9b986540e61ea64d7f69" + + "1006b86ce61565da75eb16a8b4c5865ca4eebdde2190e354734bda94fe7e" + + "12ff47dcb5d5e6ad93cfadcc491cb350b09ffe391a157e14b65e3a211b5d" + + "4e447c3ff95571dbab33a83126d68dfddf9383b4359d4103ca64af1e6963" + + "d09e17eb944aa71e76711dca33168586bfc44ebe9fdc55497d83f238c66d" + + "bcb16063bc85635f0f1a6280563bca49ef971db96a41b6ac5e0642643262" + + "61eb4662f3d6ad4cac826db895de22c9b8aa35e6464a7f44e1ae7238e355" + + "068d68754ffcca76c50b7ce7ef9bfebac9eeab32c87d059cc7ef2adb5d57" + + "c7419adb394eef48441952253e8391e555730e29789d6293c3696f441449" + + "0aebe2bbe541e191a6652ffbec1192f0f9395b7ea370aefc1f1cc8438035" + + "d7681f12f1e11d6e334da188b10c302fc0f4bcf1de448090510a8f1d5683" + + "0c943a3c388b33a038c26741a4cf3487313f755fe7a28e25e44b5383c5f4" + + "cd6ef34d7dd73462226281899dc3f2e69809a0150f694673f31addc89888" + + "072a7d4ecd63d6b90540f9522ec05829a7f17d48728345ad808fb0203883" + + "3cbd018d612992a88df944b8e34a70920b3f26cda2e8bb16c3aa38b12b33" + + "b395c9ba5e809f60ff05f087112151af1b5987403cff8bb2dce79093f431" + + "2c744f911a6f3091e4f9ef9375c4dce4c241d2f6024a1797321851ca316c" + + "4e460fc060e7839deaff8ab5e8bf682c0f21ab6952eb793cffe690db911f" + + "50b11f56ea352942c43bfff51d4360882754faeb7cf28b6b32bf7fc9ca71" + + "fbfe1d72be05b8bac9ba513d731e2c9d13d6f2f10eb926edaaf0e3996656" + + "da8718a8e103c59326529e91ebac6ed52657c9690ccbf81028cd9fb189ec" + + "4de94fc0771e53302c8d9082835a68780cccd772660a110a1b40c57bef3a" + + "c1d69428aea549ed17663a96895a66a3bb5ff6ff61dc64908df49b760caf" + + "a5aff05e2766a418dbaa1e7d189a9edd55a04fee8c9d6e506d299abc36a9" + + "d67be035fea5d220f41d081af67615fe627c4dd04bd8659c7fa4f57f35d0" + + "db40d9684aa178d7483ed5d86f04eaea412e0ea05a4698377dbff4fc3a39" + + "1f6ce0cb833d3118d6c69319b511cce65fdc74928e270da0c537f8201eff" + + "77416155d4a39c7ad38c22cdbf7d2b7ff7d85383c178a835ec604c3f9ee3" + + "7399f7dd826e34f1a35ab75da44ba56f86097ddc0f3658ef5bd65a24f4de" + + "4255d0b03411a9d7f0ddc29e33cb865da23393471aa94e6c9e72e789206d" + + "3ba118aecd39727068f528f01b25fae2280d70033e4ee46b41b864bb922e" + + "001d8bf46d6fbaa5a594e926f45eb3a4d2f074506d7834b606f43c89699a" + + "6db00b374658d9333700894d440a712a1f25f5538f9e7c8ee57ae7e612df" + + "13292c8ba9dbede4fb77cc6c8944aaef59ea6ad3b36db398f4bb0f82d40b" + + "44879835f224d6e05992b1b8a68dd58c3dbda2fd73786492ee48c7a25f87" + + "264b766930fe9427487504fad17f8d230934f044e49ba219f26ead728856" + + "cb30eecc33a3946d3b1b781061f2458c7c46f6d96f3e06f369f97be91835" + + "f23b38347d1e381ad5be4419275772c2abd549522a0203c1ee9c96faefe1" + + "df413c4b7b2624417890e0716854b7092b3b3b368cb674035d3e6bab2357" + + "e7c262b606f7141b6dad2f6145ebc1deb7597814719784f3c17848a90ffb" + + "cb0289e2f3cc7da12442b837c4e47f468bca3eb4e944a31c48562c2f144e" + + "9e920ab5e4cf90a14ccadbae29af13db38cda911e3c8f6f525e6722809b5" + + "31a4de1926ab12f643d25af87eb8610df59eded6ec278242247dc69a4213" + + "13f7c2b26ae7a917c1bdaf66c56876e9104d40b59e6ca1431ddb77fc89f3" + + "14b46a154cf127688564a4f9e120d7b5816cd24a6e095dc8ab8b43bc3639" + + "329719f0e0f723e2f5136d82638e2249e648ebca67cf0306741e9e8d45cb" + + "903bca85485c4007397c88a1ce07266f4f611b96b7e0ace3074247a7dfb1" + + "cdbbdd66e25e172fd2bda74abde7f3b4cb5cc7ee7859f053b2f04f9de03b" + + "a8e96264117f502087c3ddbee8d850bf3618b4de90f7b3e562dfa57e4426" + + "5357236e35e71d1669226d63bca50b1b944ac07a1f794e73e80985689b25" + + "f18fc709367d63b8639d71865cee667536040be827145c08cf3e57a66678" + + "4c81115706a146eccadc7aa1a9f074b47e95bcba7db8108a13279077bef2" + + "64699fb87e5abf5b05ff3879d7c7c5169c7cae817c13f0859d4e9c05db0f" + + "74c045ecc30a51e515feea627da387ff780719395b5b9ad93179b16fad10" + + "5856049169dcebd43a7f39c549762405f807378e854b1654a1179d895ef0" + + "85aafc72c7fe1e0e1cd3abf8e20935e331145bbcece4f17ad24ebb6c64ea" + + "73bd98a7494c134859206c9422f7c4a057db0ae0770c4bcb08c1a6b9ca4b" + + "7dd8c1cdb3e4977c7ce6c1e79b9d6ad98e27d2759b53cee73ec037a8b686" + + "f1ff78eb8421f41c74ce9c62a90d38b75159ec925f232e0db71362f31e29" + + "4336f5580a34b26c5a01ee3454cba227c7f400f6889a319d7121dcea27b9" + + "584f33ac796d48a9a24cc5b6799ee12f10725fbc10d7cf83e4b87d9c444b" + + "f43e2f5ee49d8f3b531ebb58fed4234cb8bcab1b8b18bf50956506baae8b" + + "c1b7492250f3adf64294310387f1d4bcac12652895d4f2dce26f380733ce" + + "0b5820e9fcd8512a1585a49940a32fc8875ac3c9542a4270602e5e97e720" + + "90ed71b51badb775340429fdbe45b887fb9ee61cf9e091c06092cf0a2129" + + "b26572574c46910cb458bca7c63eddd29d89753d57e568323e380065794d" + + "3fa1ffb874543f5b0ddc702b087e91e22604d9600d37fa0dd90d7acb2458" + + "4cd408a4e66bb781dde5f39efda6a8fc26be0d08ffdf851e422ab1500c28" + + "bf6b4c85bdfa94e8aef5cda22870c39ad49c3c6acdbb3b0d58cd05424c65" + + "20740b5c2bce4336545eda12716317df58e6fb764fcb3004f5248c5ccd84" + + "f63abdc0dd2a64e447c0de4da4a1082a729d8ebe14810d396933085cde18" + + "318278481fdb9a748b637cacb491f5234bfe16b53a35da6677336baeedb7" + + "4a28c19a412e7812dace251446d40ec07afd63854c3dffbd5c0f6a9a3cac" + + "ee3bab07fba94800fd1fa0fe44f5f2ecb2b4a188cd02b8a2df0728347c50" + + "7d0cc58fcd5d54dffdbda11dd1bcc59758396ed8db77498fbe13238d3d8a" + + "0040194dfe66811542ddaa658094a9580d4e4b4e29", + }, + { + key: "1285f117bd90b70ef078ae62f37d2218419e894b7d334759ddb2d88833b287b5", + tag: "429b2b39195a10357043c9601590a277", + in: "00ef065a1adb4ce7108b497813ccc748933fa8442689a7cb8dc7c1ffdbf6" + + "c09adfe05ca2cc5ec3acb7493f3497ee8f9cd9bb8a4b332c18e33f78114a" + + "c8f9a72ddb9f13494e934ad711818909831013ba195b53f5e9e5b4689399" + + "6d0b669f3860958a32b85a21009d47fddbc8697b7c9b92dc75d5060eb4fb" + + "40aed7a1dbe69dbbeb6296f5467ea2426cd17d323671fa408855bc53e5c2" + + "d111203ae38cecac7719c0bd7f21f6bd6a1588187b3b513983627b80ac0b" + + "300b7fa038af1cc8512403ac2cea6e406595202ec3e74014d94cf8780ed0" + + "33c570e887ca7fb35ee4768202aa52427d02c24e63f7f2cede95ca9909e9" + + "dfa86246a27db757750667c198c9aff4ce348f7ac51864b36ef5695df713" + + "d17b8f561a972d0136bd9ee9aa16079c2ab5d29ac9ab472255ade05dc49c" + + "b966e0c1c04258ef9ec59ded01f402d9fdcd9a2020a2038a8c78892ca218" + + "30136069485527069132959dab2b81c73ca590fde2a7ecff761d95a54d63" + + "a2664aa5a6deec163e46b5225bc98976a4f363063b0f42e29f792d138af8" + + "eae68d3854b5c1985d5cd1c9f49f529b0b4d2c936887b5b92cdebacef992" + + "c35e0b7bbd52114aff8c6b261852e28e451b02099814f809b0289cba0586" + + "04a363e3f969aad3d982f645ec4c549f943fb360fb8fa0d5a597bf89842f" + + "8ced6014a5b2590ef71524a7ad50fe0ef0e2f81b6e26b99f9ebbc8036549" + + "f7eacbf6ab884710c6406ff59788e03ede35c30d4781ad5af171e0623e8f" + + "cf5344d71165f0475e256e9159040f702b359a2963116ed135dd6c1d111d" + + "2a1e33e15c178ca4f02c5fb15593c50cf9a8a492f01e04778dbb81d26c99" + + "0c58cf50a9bcf4fe38fbfc0fc0685d8bd422a773c7bce649f7a86c59118e" + + "f5f857b2c72508cd1ef05e1a0c0b7ab4687fdd57437092eb49bf41a9ae8b" + + "bd98272ea2f8ee2515ff267fa6ae892c266a7effe61ed54984924aefc461" + + "6cf483dec024ad666bc797beaa429a742d1b8806f67d451b6d3a85b4d474" + + "003cfe9e9dd906df47da5559c41f15afabecc3e6af279cca0f2a200eb2e8" + + "31437e034d457fc880f60f5ae635690bce82bf6d1ad6b4f5344ec042bf25" + + "7d010273c861e3ac516e9ee2bab3a255f570baa32298467bf704bf6d9076" + + "a4c0b08a528a05cd1fcbdf51f3885fbaba7891a144fc058919903b269b4a" + + "29f43926eda32c38853b814a7d528156c223748d674d8f7f5448350f011b" + + "bfab1511001b8014e20fee37ccd4a0456f638c197c86dc116b34f955c0b7" + + "dee10bac5ea0c2fec8a780ac05098b51b902ca6afff4db3c6fb4f761df79" + + "b2039dc5f16d9402442a6fcf6c4297769e6c36824d908beba8e584ea0b3a" + + "91b9017baeefac651d0307bd89f517789236c0693c65a5a20f244d39684c" + + "eb810cd2ffd3c78fe9285d2eb9f55d133b86113efb8dffcbc6d258e84c38" + + "2dd8f4d7d63b65672516d9bfcc3310a79ce244b60d380128d529487f99b7" + + "d532d5f5c28fad8b9a071fd2fab8fd98f6d7ed9dadbd2fc4396476eba6e2" + + "1a1b1cc594a31fbd3418d98e4aa736cab285a2786fbbd4650e49f9b080ed" + + "3fda34941c28d25545395e1408fc3e60730d0696061f821a4d24123cadf2" + + "3af3d37ba7ce1ba3cde1368d468f136df82c02f9be9210022192aa02117a" + + "ef5ff70bcfeffd47bc37b920826a4d3db001f956939abc0df520f3ec1613" + + "ba1c4b3385cad97e42bfd15a3150711fe86ba4562f17780cee1cdf198615" + + "ca06270db84986f33e1d53d552b0da82397c496a23c7a78ca7641a908e71" + + "89249cc657c0431f1e09ae0213f28a27e6267e9d17b5bba0ea4f3c21f266" + + "fe538e215ec62f85517ae6bd87799ac5ce68453f09cbbc50d6e2a168f0cf" + + "7166ad50cb65b6c76406c326573c00e04a3186251c6181933828c58f4198" + + "f8208c4484805639b0d428fd05b57e4356239638f458a84000c7a7a8de62" + + "ec25b54d1e39d2579ec9c512fec475f243576f35efc02a1cd6b0478e2dc8" + + "be5f17aa4e3849cd42e76fbffe6e7d6f912d6edf80f718f94a7e48e1fc10" + + "6cac29627d9d4b82f05a30cd7c739f7f3ef7ea368d22612f189da450e274" + + "de7b61c6361521e684d639be5af4cb11fefa5fce6f8a5065c90873e504c1" + + "2c940571ea7bd7e9221129b83039d2edb069e8b5bb68567d8fcae34c6ee0" + + "cb94474d8b056cc3c7403873f2fe6db3b567a44e702e4f4813b2a264231b" + + "0a998207b41916715ef94e5eec281589d0a711f8e74be32bc60f43d693de" + + "77f21d5f7eef892abe87725f3d2b01d9ddb6dee15f40735a8fb67766dbcd" + + "020a93b8eef4361dc3a891d521551f65dbe6e3f68c60819b0a540b0991c6" + + "4449d207cf5b1c198c17ad6caf3adc628d09fa0baae7a696d84e1879577c" + + "ffe9b3f62669d4ea5ebab6364f08c66d170ee4a94d61fb77d60b33dd6b60" + + "650f034c5c9879243d5c16f853dd7a89885a9047a341b076912d47872b3b" + + "3de49edf7451b435698ac4e182d16c339be83e18531a34aebad36c5c7c93" + + "aaf121cf99ff92d3844d40740fe001eeca9ee71300d826bc3cfc87a29d39" + + "ea108a3cf259657ec4b967fbb534e7513ef3a96bffb35abc5ce0e890696e" + + "54fab515af3d2c0be6e003747504e486c0ec6e30fa4ca79d6596ae0425f3" + + "396e40fd37432e52c74f812250dad603b3502f97ada48a26e39fd4d44584" + + "6591bfa5ffb3770d95d3dbd49e9c3a38c6305796b8f7d79bd0845170925d" + + "575774445299bdf9d3f8ad3dc2dc5cfd3ef0293b84d6e11370851af05ebf" + + "b3510a22edd930797dcb76b759a9b5a77ed8dd5130e79ff5ac44b01901bb" + + "79603cecf674202bc5d84076ff41b3c806454ce80cb9e5fa9db77294d20e" + + "6d3008ae3017aba712862ecd4b32daafef1b8cc8b19ee8f8bc3835e2372b" + + "5cec66222ad5ea9df753c033508ec43c8b5995e88c36c13ea3465c8bc462" + + "ae0a659d9767db34499e9d01fb1588410257d6f588b3fdb766a66bce28b5" + + "e0880f8cf988a2e5eb5bf80cd7d83192b7392fbb2e3a07d51aea2b6bfac0" + + "d74d304f56d5af3598a0712cb09c04c5dc14194eca8e1b9b29f88344c0ea" + + "55638c0f8ebb70b6242b797fe2525fa1bde76293dbc0a66ab4715e6f9b11" + + "f7ecd8f35a20ee4ff3552caf01bb307e257ec0576023d624d6094d43d25a" + + "aadfce939a6808f8baacb2109c3de50a1cfada9e384cdba3e97d2c9025a3" + + "2377bb195fce68c5569d2d1267e1bc68fcd925ddb4acf567fb29ea80517a" + + "7e4056fb014cdee597333ac2408157ff60cfa1afdc363a11fd4883308cab" + + "d9a8fe56c2b41c95eaef854f20bf5941ed23156d86de3bd413465a3bc74d" + + "5acffcd15722879849c261c1bbe987f89a1f00b3069453841b7da667d566" + + "e41fd894d94de44c23fed08d9bdffb723aa8449bf236261240d865efd7b1" + + "74a4460e5004ff77f4196d1d421227dff7c78f1726df7b5eebddb4bb5f57" + + "5ade25296dda2e71ab87ea2b44ef2ce8742a7ad5c1e7a40e097eb336561e" + + "865515f7ee0efbe01d5a928f208f7c9f2f58974d1c11af0e737c673dc446" + + "1795da9757010cefc6e7f2784658717938735ed8cbcbd7981a1bb8f31cab" + + "b901c87a3218dd1195c59f64d0bc3ce8b72580fe38e6dbf1181e0090e5c6" + + "d162df9f31cc52fa6a8ac61897e9b4b3cb0ca2bfb38a38d9b78e46d775d5" + + "7645d2d6da16bda8edd8675e2ba121f7f85400cf7cacb9ffcdfae583fb93" + + "753d07985a00afc3a4e26c9939a5116d9b61196502f5d774ab4c7fb6cfa6" + + "01bcfddcfabfcd28055e858d7d3c19feb6bd7c02565add3a3af61bfba8b6" + + "f4b52c072a8613e878368318383143059a98a85ba521f781a8983c2486ba" + + "b83f5b91fce02acee0be8d0dda7489975f0506c8f363b5adc48ba971adeb" + + "4e1c830b5f264ed42da36d2b5ce2fdab1e63333b1061ec5a44ec1b6e99da" + + "0f25e7f7250e788fe3f1b8e64467d3d709aeb7360720f854afe38e190cc0" + + "925c6cbd77fbfccc07d8beeb0ce68e47442fadaf13b53c30a03ce317cf79" + + "dc9155ddf96814583695f15c970fd0b6cea0b04b1825eb26e65ea9351bf2" + + "f7a841ddaa8c9f8e885b7c30b9985bac23d3ce777b", + }, + { + key: "491ebd0dddefc9f0117176772f9bab61b92a1f1de13796176091c56d1e53dfbe", + tag: "fbd3f884a3dc2a8be06ce03883282e1e", + in: "953b9a40789b206fb507ec2c5e9c88ca1baf25ad24c11a62f664db1da8bf" + + "dbe9b54f8e93b0bfb4adb12f8873096b8960fd91eb92a8ddb53232ac9141" + + "57caced33424cff943a8db129049af7e7b733afbec6637d8ee4f39d063e2" + + "be241cca6a339e48d72372efabceac57220692c40856532d95529adfae87" + + "a71c72f30244126d01a875375ad8836ef8db929bc81027935042a05c346f" + + "bc94dcc057db015e55c56064d2b11154596b813ee64b73bcac05d2688bf6" + + "f1fbb0cf3f8307b3df44c3e2dd1d226a4d0e9dc5f7482bada9611970f887" + + "f656dcb19ce1f8c5c86f4cbd1e4f49b18f170ecfd184028e769e79d7424f" + + "d01cb315897c21111f53f4d41c3b71402eea695272cb5b4e5f33abb9df50" + + "cbdaa55ed629d3ed7d93b43e550295502db1f2ed884afc320518e88be4c6" + + "b62a13f8d3636ba091d07dbc6c20c7e7fda016c05b2fadcfc9ea32f4ee2c" + + "4893de78ad8a1771aacf6efdbd8fb1f6ee9b0572ced3edc6313185b5d398" + + "88ce77950aa4c5201a256e3ae3e74f05b70faada14124b35b105a70e7769" + + "7184576b69708eaabd36e0ba885fc6bafd5738a67307a1181792333cddfd" + + "a4ef19c88497c82fccff05a8f9f732fc7505f0467a14e135288ee018aef3" + + "d0412f6b0760573d8ee4ab455d2789b4d22a42eebdf60616fe403627cfca" + + "fea672bd0a49e8e7b80e7b7b8feebce3381f2fc16819a8996a99ea230c3a" + + "84b510cf2e0d914610d646a2f45a14268ec1d6fca03d0aea5c9ae1c8d519" + + "b0e8b0f6fb8ad176b5d6aa620b253cc492b5e5645353fbd9b6c02bea48f0" + + "286e2c669782b5ffefa4d8f3f1037151026d9cca78e7808dfbe61df29e82" + + "951d7154f3c97606cd1e99300012578ea6a776dcef0811338b56606b51a6" + + "9893fe68f762af6c9c26066b1d503e64877d8cd988b443af66a36af8bdfa" + + "41b4dfb3721d1d81895884755b9c52527030afdfaecd66d4638fab1d1786" + + "3d5517ef7ee7d081b5555d24991810f1edde30930fd392f817cfe632b4ca" + + "6fb0460c36bde4a5620b9c369bf51c7d870c43998b8171a553d2f643fe8a" + + "58aabfce8cf7363ea978ff4d53f58284db822ca95b80306ec02a64d26a29" + + "c98520f1924c70d161682c54d08a2c48f54bb72980a8cf5babd0aaf0fd72" + + "7d5b1b9d9b731dc49bad228fe83f7347750e277a4fbd526983c206e075d6" + + "a03d68957b3e925a71bc1ea7304c77660d112a5d19fd21a785d4a8d7f2eb" + + "dc4183376d8125341eb28b2df5be0b4e04bbf95c47d2fe2aed939619cb97" + + "79548b752f57b723cf8295dfce69c9b7486b75a4e900f91926636f3fc78f" + + "7b7720a5151abdf5868fecf1e1a1d830cd6a4c5e3cd739da4432cf1fe2af" + + "a1090d6a1eeb32e7236ecfddb9d07b97220ab8e23edcc93d91abc11b0c30" + + "460d2027869d1c2487070cf60b85ad0b8bc5df566f6fdb0e58fd044da530" + + "6d277e564ca6cbfa820ca73fb6201b240a5a94c4ecd11d466cdc44046a66" + + "32478221bfa69b3a2cebd16baa302a573c90895d7f4cab453b11e3a4d8bb" + + "b5a9bf264781ce5b9796e3c47d0fa57f46b923889af4d073270a360dae8d" + + "51d85ea916f14787c6500d2d906ccaaa92d20d93edd09139f79bfeb5fcd9" + + "8c1cdbcbe9f2587e9c9094e3c4a32ab9ba56f400b929e80c0551f953896b" + + "e8eda6ecf22e6d4a541957dec21d6a9cf388ff0ba58169ab934902892a58" + + "86e1126b16118e965a271495ffa339c49466209ed3875b568a4290b7b949" + + "69d0465744a3c2a75c599c3a04ab1a3fd09125fe8f45724b2f48c7822b9f" + + "ef95af4b758ae66a8b6646df7a0a1aabe2a24c052fd6d30561cae0389263" + + "e3388c4c1effe431a04356c334aac64f36593544885c4b7295b57dc39638" + + "b665b22dcbf7dd6da867615de38c6a575cc66391135d47f8e1f0c73c6129" + + "17ada4099723933a758d83311b384364263cad5fe14bdd7c825d9601c400" + + "3537a5aca7f9da4710c132ce8b0f1464cee625633ef57f507739a0ab1cd2" + + "21ae634d4d0b3ff07e9ecb1baaef0a82a97279d46543a0464855cd62c07d" + + "5e890265612906a9eac88bec07b1dea5f67054c31ae40f8c673296cc5df7" + + "f0dd8cc9e643b44fd90dc2d1e870ad8acdbe165237642fd04c00965837cf" + + "bd2344ae830887a5719a3c16dc8ec08bd9131d055bfb959b64ff4cb638a1" + + "002a4fe02e369871cc4e3ffda17dd85343e679fab43e11970e60198b424b" + + "676ab17fb0dee10cc9c2e92b32b68d5b05b7a559176f822850c0557ed98b" + + "7454916e32af549a0027db95f02b88cfc5e7e05f28f53757dd97cc0f0594" + + "212f8801e58043cb17b040413c226dfce2104a172d218caa4353890de17d" + + "be1f53af6ceda24b8781801516cc51de9ca459e469b3c322be13d8c9541f" + + "755c518ca41a0ed42e44b9f87faa2a968b0292216e9f3d3e8987282103e5" + + "016fe9f7681496e1e8d663eb2d8bc30b41d735465527f19e336a98d2dc54" + + "d7c020bfab30fe6c62cbae7d09f84af69bc2c51a1839ffba15015d381ba0" + + "a44a3758771c4f18d13827f518f30bb74f4bff29a87d4b9e949f1063f63f" + + "662721cfd64ffe1dab3761852387f78fa83fb48ae2c75fc567475b673da6" + + "fa8f53770b6e5a3c9fad951ec099c6bc1e72d1c489e1ae620e7f12ddc29f" + + "ed65f29c65cef75014b999d739e2e6e015f928a30f2fee3f2e59bf65b54d" + + "89948bf2bfde98b076e5460643952befd02fc1b0f472a8b75195c53ea296" + + "6403b9028db529cd04b97231bac3068855fa211f4d976a88bc27a0088f04" + + "576e2487ac0467992066ef7667ca8429faee92db38003728e5c219c751f6" + + "6f011b5d679fdd957f4575a0cfb6b54693a9624f2c7e66c578f5f0367005" + + "c66addd1e3ab7ea1ac404e357cbdab9438b9b4f80b3a6761b864b006f1df" + + "689ae4c0434b06b686d5353d3e421b57381ea24fdcf6199195ccdb3d5cf4" + + "623a6bb1f9eba9b22fa15395f65f8093b5f90455061c1cbf8128b44a31e3" + + "910862a59e187aa7f4d22e0317ae6c177cef24eebc44171f70c25efac73b" + + "38ada0cba0b74f72d1c171277a734819c1111ebe46d5db20a6ff20e2c1a9" + + "a57edae95a3c1f80ddf2b12c86d3df0078a7bf68695b16ccf92053c727a4" + + "80586b8d87d0d1772e456fde0c20a7927f351a641bff5f22f9ee2217b6a2" + + "d0983c8102d7d5356dea60a19e105ce366b9d000987c8c33396569f97c56" + + "2d0fc0bc5859779aa10efd1f8df0909c307a9110083cc6d9748456c9bddf" + + "16dccee52b7974867cec718bb0b76b3353379a621257094277a30148ac38" + + "e5cf67ed7cc9c1bae12dbdeb99d7d880ce98e17f0dc93c5330d1824a3c9e" + + "ffd86f89e15b59a4bee5a48d4f674766896e187abaa39917b83f8d2f3265" + + "bbe7aac44c9f8d92f775fe6493e85ab44e6e28f79f28eff156c21e1abdae" + + "d10a291b88c4020b1ae8be001080870847a852d073e82bfc751028ac62d5" + + "6aeac1b18f2cff1c0c7d336bf08f8cd5099d9d3b28f9e16077e9caabab49" + + "f2d234616a7522a6bde1a3b3c608df4cc74a6c633d4c8068138abda8d26b" + + "4ca70f95d152888fb32bdee5dfad8ff4a5b002a0a327c873656db8d6fdd8" + + "ed882e47ce8e47c729e1292db9122ce2e9fa275f9bb986eb7e0a1dccb7cf" + + "abd0449c92fd35e2aedc4aa89caf53bcd28170cae85e93f93988e723a896" + + "10cefb4edb6fa545835fba3107e21dceb272c5a32da26fa77df070f41d7c" + + "ad1d68b836199ff0f1221e36b9b976b5e69bed54b5bfec67fe9cbb383484" + + "696265204797634594bc335150daea92dbc1004f613b4c27bf5c699debf9" + + "4365041b5a894701da68a93bcb61f4e546c553fe61f14ab0322b45915da6" + + "ecacaa093b0071f2516ca8c3fef2f1e3c403993d734403c47bfe5f4379e9" + + "cb5b613fde3c0d880cecef4101aad8b8b1c60a92ac5185f6c243fdf1711b" + + "0b56f0fd8e5ed6cc0f99da888e4f156455a0f0eb365b8964347eedd15d80" + + "2f297977af667ed1376dfcc610f5152421b97afaaf16f9db57a435328595" + + "b9aa00b5ed9ff106c66970fafef379f4d2f98f2c5984ea05aad64651fbf7" + + "7968c8cbc4e959859b85302a88a3c2faed37765f3f6ced59d8feb6c72e71" + + "f9d4497d98bccf95fcb650f29131e1df1bf06a5443f8af844aa1a7b5a68e" + + "bb250c7de3a65ae9b1086cf83f832050e55030d0f67c6a54ea2a1dbe18e2" + + "8a96c9e0dea2966997bfc5c5afd4244e3c8477c4f5e8bee8fc8ca9a5cde4" + + "d9c5a2c7f3d2e811b1de7ce4279229319e432674c609b4c8b70dc6172e9e" + + "653fe1969bbc2cb3685e64fd81d96d33", + }, + { + key: "b41db44465a0f0d70093f0303bbd7776017bca8461c92116595ae89f1da1e95f", + tag: "d8a111a09db22b841fa28367ce35438b", + in: "b074b0984fb83749586881e8ec2c5ce9e086cfb2aad17b42b2429d4cf43a" + + "0400fd15352d182e6c51e9338da892f886f460d40bd178d81c52e9ab9c1c" + + "bdd812594e6fe7a9bb7fb729c11328d3288604097600a0c151fa3d9e4268" + + "de75866558e9f47d8dd331994bf69f826fd4a6cb475ae5e18365f59a477a" + + "dde7fbcf7e40b4e3dee020a115830b86f0faae561751e9b596c07491c42d" + + "e02fc979e69071113953729d7b99f1867116d058a90f1b8c0f9ba12c6322" + + "4ebd1b563a87734f5d6e2d4e6715d5f0213e33316500cc4b23784f78a9bf" + + "13fdf99bfe149cf47aeaaeb9df1cee140c3c1264fe89bcde8acda6bde16c" + + "e3d770ba51950b67ad2c5232ae0cff048ddfda8540cf18e673582dc96987" + + "4b127f655e7d4e08859f2c6b95403cd5b4e2c21f72bb872e49e592306286" + + "48ba1b16fc9637709636b198f9a297aec364d4c3bc869dcad32b1830e434" + + "b556b429136f0012a0a0b6fb3797bc8668014b010ea51674ef8865348dcc" + + "197672047fcf72e6b6910a0e32a4f110d85e28db0e338d9cfdec715a8800" + + "b4f007a7951d09e41620815848c89f8768344c50bd522c46f64ac6c98e53" + + "92176651961c7a70b62f3d1819bfda674e2ecd3167415edc4b97419e8ae4" + + "9974b56cd8d52e1d05b82610b59606a750b34844ca33bfc9b21fb970738d" + + "b66f48928df79cf67730a30b0b612f8c15c22892120548ab460a6b9bb3ac" + + "e30554c86c9681c797821a1b1ce91d0e87fe90ad4097c974cfbdfd5c4c24" + + "a5f808f388e1b1473e858f48a387614501c8c39d6973ded69b1764663cd5" + + "166be02b596a49e392d637e3d8afc91323f7450318b79d5488c040e346cf" + + "0cee512044514b570aa66bb98d639a9ee23a7cebe28474592623d082873b" + + "73efb3eaa4721fc4761e15a390497cb13cce181107e8b1a0186b9e47a5a4" + + "b67a5be3cd88a43d341ef63f10af6970aaf56035db938655020809033a92" + + "8d4fe6d2f5424fbde2fe82adfd991d388edf293cb4e3eb68d876f225a5f1" + + "58208bcb1aaefcbc28d6763d267406aa8d6ecb413d18cff7a318ba031ba6" + + "0ac4560748c248de64eec56dd4540124b38581604f502d94a2004f9eb1d6" + + "edb009e16af6c6d3ccbea79b10743da98aee7ace407a90c6cfdde694f36b" + + "e0271e722618a457be68619b980754795f4ac95ebf4f1820b85ca8e3fbff" + + "a2430f8e01ab422d7140751f7741f2c921400dac404b04e049736738a87b" + + "6f49bd54b1b447b922c473831a65f224ab84fc96e4551a0333bc6187e15c" + + "c0f0ad628068bcd7c043bd1e3036ec01e7fdc3d157476149917baafaced0" + + "15d09fafb92181a0ec65b00c9c13631e65de184377416e04d3d93b847e0e" + + "286c1d88245d4d550d30d4fbfcb416ff26a39a94275631c2deafc7cb6780" + + "f149e4d0e9c4515b708fcd62be5252485407a6ceeb9247de34e0266ef384" + + "976f6d31284c97468b3b03e951d87a5a00836ea303a266147a79ff3431b4" + + "b382e86c74d92661e0f65e266b7d569c03994b667a8137f3080eda2ff542" + + "0f0b52b427558dc26932a22a615c9e6b1834a251c6b68fdfc0bbe0e8781e" + + "36adf669f2d78bd23509ef7e086634e526258e8d11a1e0be0a678ac09c7b" + + "b4e3c5758504011e701dc85997fe2a3e40c7af83f032bdbe7adc10ef1e4a" + + "666946c2bf31dd8e3a383211c9684d5302f89dafcf77976d5a02c14e2462" + + "09d2d99918e82402cb0eacaa12032ad8316315af1b3d3bd5058f7c935d35" + + "ef0d4e71373958fd5e4140a9a586d89c53e4144c00148a4706a524896eb0" + + "5b1479a0de5d3f57be46b3f5fa4e49bffe027c81a33e37abc01a4cafe08b" + + "8e21fa86b42be52d75d6407e6cdf399de7aedb9b61a6917b2677b211c979" + + "33536664c637a57ce2234e3319fe8b4a77d7285ae6347464dfd0aab3e6f1" + + "178e0029686770d3b0dd541490b097f001e95f27efe8eb16e4747937d643" + + "cdefd49e586ecad541270cedc3064bdb7c79f086bf1fa8c666304d977a15" + + "54ae268881e17d8bc3fe51fa9969f7e560e3d3e050424febec0998b35f2a" + + "7378b2c3e384cbfc80c4987734d76c78224cb81cc5376f88f0ceda28aa50" + + "44e956537c3ee209071d84a66173384e0aa466d989759fb1f2f17fe627a0" + + "ffeaae7c5a3884b237f5151278a07117c2e833f1815c7e0e0b1611f25058" + + "ca338d21deb1a571faf1d0486667cb7c58e2814c3722d24fb77ce1b7e018" + + "2ae5746442b5ad00208b17c0a68bab4df8a8f36edead4fbe79b4c9220dd6" + + "acea6d23c7caaf6ce7cabeeca677a1c764d610ea6c7e994d6a9c88f57fda" + + "ef160b251e7595578ea2cc1441d480c14b8b6945e76a001891b1f214979b" + + "c52ec15e9480d706a40cb6e3b259ee99a9e84e63a738f1b52cf71c8ecb04" + + "fc833c2c680bfed587aa1541e5ffe8bbd7b21302bbf745011e559f94f952" + + "8b7fad8a37f6d855306a5be22725859cc950bcc334179d49564af3b9c78c" + + "e1de59a9cb45086a33856ba7195c17cef573950155bea73ed16645768bf0" + + "a5cefce78ba3ff98a54a8e8afc5dfcb0d422bd811ba9b7770a663b081dbb" + + "40aefffbeabca955a9638830f0c5d70663cbf5b26067cd061c4a3f5cf8fa" + + "4b6678d82d9a2aa33f8538b7499a3466f6b0ae2a1daf280ab91a6c220684" + + "12705245f353b4b83db50bedd3bf99d42bde6363fd6212cb745467acb007" + + "b678128f6580629a06171f7f3af272f8900b801af3bf47439167871e7b0c" + + "33f198333992a6c52c32be46071738cfbf245937d48f816ebb88ff0e726a" + + "dc41de4c771ff0bd320a4c0b1fcccd9fd6c42ec9c5185943c70e9a4b7c26" + + "a980afe104bb1f99576671a254704c7d4233eaf9915e1d56c103ba9f6e8a" + + "46aff466933bf58c9842796ae9cd21f7ac6aa96ef42ca54e390203bac354" + + "b7c1de7d1887c48255201335f819020e2782a2ee8af92ceb206b651ae92b" + + "3f4fdefed05e08974aee0a353d104b1be9a5e75c7f958f1981271b0a6928" + + "05a7a2f28a0448d86102b4fadf9ab4ec2f98e31e64fcfdf2b524780b3342" + + "7a2a3100c2032fc93199f3ea7a9e8063fe73282dcb1fafaa9496c7da868f" + + "dcf33bbb761df0bfc6fef30fadd2b6efef4fd3216a8aee48a2ef28102491" + + "cf7278b567c272d1064a277eb193b3f6f01df641ddb729f72454943cbd3b" + + "671ec077f9e3548f5f57d063c653ebee4f228a78f8a128d26f7f4b44160a" + + "07e942bab87b2d043c77ecdf10c1a419e0a1c4162a99c21d4abae0558b8f" + + "4dc0b7f1ca3892a6babf71f2f70aaca26bb813ac884ee5d71abd273ff1c4" + + "add230a771b678afbb12a1ca7fbcb2c0f5589c9ce67fe8f78a8db87825b3" + + "09ca34f48ac35aa7ac69c2fb2423807650fcf47ee5529e9d79dd2628718e" + + "230ffe5b83f9d5bdfd9c5d211282e71cbcacf972995bf1b13d21419f7fa2" + + "8829ed1dcc459da35883b9269a474f7fceff01d44ab78caf1ef7d8117f50" + + "cc83eb624062b149a6ed06ddd1cd1feafccdee7122353e7b3eb82978ca69" + + "247fde52d2d6cfe7324f04af5259e1b5c2460889da4541b431ba342a1c25" + + "3a1b1b65fce7120829e5466e7ad2fe4e0f773c7c13954a9c92d906c91aa1" + + "de211f40916596bfa8245344e257e5907a2c49ebcc864cfbe28663e700d8" + + "472c50355313d5cf088e9e8a19cdd85bcfc483520498c6386050e53a3ff8" + + "1e2b77b55b116a853d71f60d621265166cd7e95ff5cb4466226d7cef68ff" + + "d0a35b61e76a43cdcfa8da7fff9558e2f89b981ec6be632b126303ca1fe8" + + "53d5c628d967d39317b60ac904d6a882beb0746f6925a86693aff4deaac2" + + "e5b64b611de86767d55a6e11221605508b1c5cc828251539b1b6f65c2c04" + + "8e65be5422c1b11194eb687d906c559068c0a810713b23b30d8b17f10df7" + + "0962c5e7e782aff7bb95adfe4cba9d90b0ebc975fa56822025100b5cb8b3" + + "8bdc8928c1a2a8034dd66e2a763696d7ce6cef4dd586b83f7d01749d37fc" + + "4fe8d7abd324d4ff1efdbdbfeb0a2fbb8b266fc2bce8e5e5b95d0089e7c5" + + "d7de4db837d1822ac8db8198889d6bfe778d0b19e842f12b5afd740aaecd" + + "e36e2cefc2cf0b082aa0c4f75684d024b8d828d8f2911fe1aae270251f62" + + "4f49584e40bb193577c9d8e04eb16c094653cdf9a15fe9210f724c7a7c73" + + "74cfd1a74abb5ceae88ea54f7e7569f8eb674529cbec965ed05bb62f1968" + + "8fdaa97297268bfeefd06eb21f700cc56f9bf7f6cecbbbe7278ada8399fb" + + "960371a2d5cdb852b11c9fa17650e614c5297bf46cb7889d52bcf49d2560" + + "720852822b75bb16524d88273cb366b84b88282da91875562e5a1fe73973" + + "afe90e5cdd3f5381612d3ba7bfa058d023a9326e403ec474d8938313fb32" + + "bdb5bf899b900c3818c43c8a0af6a061bd26e847ed75983402ee8a9cf4ef" + + "85bba5545a0d329ba81495157eda0286f1917de512fe448251697dea406d" + + "a510adcb05", + }, + { + key: "b78d5b3019688e6ef5980c17d28d7f543ca5b8f9f360f805ee459717ca0d85a1", + tag: "f01babc4901e957d0c2032a7279321e1", + in: "ba7d35b2ef8af1118bce1e78018c9314b0c8c320591e103d23f715acb05e" + + "dc98fbc618de06627661df5842dbba9f604c2d20d664e5db06e949b11d49" + + "665088dbafdb0d39d20beaca7d723f8dcdc57e9c5583d303b6cdfdbecf95" + + "7d8daf2f1c72b2a6fa27e3d18841f4841abafd334c110cd2b74efb6191db" + + "ab9b8fc8427ee17664082f31db98d30bf15dda967e20730a9ef525abe9f3" + + "f620e559ed22bf74d347c9869f0311f33da7f1a3dc858b3a8aa73a35989d" + + "b055a4a2c269c95e352259c57de8b94d8de48984ecde426d3ef60ec1c7b4" + + "41cc950f7764f55bd0cf52d069b9ad446d1f765f35d02ec104ffcc00bf1e" + + "dc1b951ef953acd19984ff1b41041bea0e9f5326a7c9ed97e6aab42174ee" + + "971ea1dbe2fd1c1f67f977ab215962b0195417170f6b7748fd57262424d6" + + "cf7c235b34425f4047191232722932213b3eb73904cadd6a2e9c7571d7c6" + + "6c2f705b5039ff75e5e71c5aa738bf4177653e6eb0b49303a4bc0e641e91" + + "2691f217296a3325431d578d615afddf47784e4618a2ca40ccecb05d621d" + + "a52f272b8cf84f7fd8177c83af1580d25a764cc06436d67171cb5d1e3b39" + + "367b46d9a59d849d87ab6bfcf3fb9bac2b1ebfcd1cef4459e74b0e1b7080" + + "dabd2dea79f75581a55de63c4b23ff67d986ad060102933fc6cce8d614c9" + + "c86dc84068828dd9e21ffc5665c809d83b09432fd315dfce5d7a4ebd8143" + + "181953e3f8716e47b0b30cc1f753e31a7d509f2dbd4177b6da310cf3cd02" + + "5db270adf98e96259a5ae1b81f5be4d5c76f502a612ca73c76b91e0ca695" + + "aa921f9489948619482c2956205ae71fffc3aba4476ff754e4878e36c763" + + "2c935c076857c5b90cd63ea4764efbcee53e2ddc9bdce54b1cbbcf0e7544" + + "d023e7c2b79419ad92221a1f76abe31a8236e370d38e2493cc9ca2aaa811" + + "30fc713d11f500fd071d6eba6861e8b0859b372e62fe60b627a96c377f66" + + "236aedf307e1d148a61bdad072b93d7d2a73367c595b1e048f7023e72729" + + "1ec508326f5424a5bbf4e010d0240b71fa9137e6642ab40c5e4fff79877d" + + "b3253c663a221b49b3e77ea307c7b9f3f72a0f3a54d0112c45c64a0c0034" + + "baf2b55ae36ea6f811bbb480cee663136474dacac174c73b1e8be817916c" + + "fd4eb1876582bb3a36cfbabad91776aa676305ddf568a86e3a5eb687fa81" + + "67771fca7b5ca00e974b3cc3e322b4bd9bcee2a87d0ae7976da5e04fa18c" + + "219fa988d4f6fce62f194b05c26ed3ae1b066cd9751a2d916d53426a454d" + + "58f9c3b2fb49374e5791b412fdee1b6029144f1ca787f56fece4f64f4fac" + + "bfe4cfd8ba7c807a83cf44008fe5126a283ab2631a87acd8e2a3bd10979c" + + "4b07a84a49b0687a45a4798ded0b5e9b2acce30e714d78395bfa8f33ca91" + + "e68b2138bd67d8a694cd87c88dcefcd101a3b408d7a9095cc6a4b38898ec" + + "c8b375f5a67deaaf73eb7e99b10314ca6bba824658bee85dd731d9a1475f" + + "976b7c0aed4b67b088f0db5ca5091273217f724969dff6cf184181377c45" + + "5722beb23fd9d097a82ea2d8d527ba6284acc20cb30f2e52af28800c61fd" + + "1faf9f4f619550e0162a1a63758e202533889b27420fe7d0eac9a47a6e11" + + "1d80054412340e0426cdddbb3c7b9b823b8db3ef58230fad7a3ac21a7805" + + "d30878d4ea78dda95c951b7a5dc552e9434c35e03e1dd88652d3714f8fbe" + + "a39936cc0717c2e0335371f2a751204f5d9386baaec853f019325edfd1b0" + + "719d1fdac3fbd774a64bf957fc54039501f66df94b5b9b82c2076c597065" + + "dfcfe58b2e215a3734066aeb685ef97759c704b5f32dd672ba59b74806cf" + + "ad5daeeb98d16f7332ff0ca713d541c84e4aef0750bab7477ea707e2e497" + + "e12882dbc0765106070ec6a722d08fe5c84a677817b28fa3a41a6117f2f5" + + "465c2a2f0eb2b8be4f36e676b4115008bade3573c86cfb1370c03b6b0dc4" + + "bbbb0ada4dedac10a593655068a26febc2bf10d869cac84e046c9c846ce7" + + "927431f606f07b92abdfd81260199ae05ed01dfa07088c56a6a8de9c6d51" + + "d61d6a6d3f9904c216ea8329467a006a3d2495a768a39ef99a21827d2def" + + "909bb743fed7209f7fe59ff1c1e710095b05f166c6173deef5c6ec4105c5" + + "fc3b87c8269c786bebd999af4acbf12d20453b125f338aee87e9509ee405" + + "9c9e568e336304d7be9ffe81d1700555b0800242d9b7450d7256f2b17f6e" + + "d46a39f67bb2980572ce73169e352070dbafd4c7fa5a6be78cf9b72981c0" + + "a01f1e1e30ee3736c59828b791d2373799854497a28a44bbe0e074925723" + + "4986696fbb06ef9ea83fbd49c45a583ce12ff10258ba06127c67b0f66dd1" + + "09f1366d8036853973d8884f93de54fb2a12949eefc020717eff47898cef" + + "306b5de068411f1e113ffdfe2556e0faedc3e27d95a45b8afc15ba0eeeff" + + "eb86da7b4324e20af80c62bf0ceb4aee1515f5912f71c6bf2febf20123e3" + + "dd3a82dc1e58a108f1039942dcdacdeb1f0ad0b2ef34488d98d6a52311ae" + + "acbd03c12f6e775e375d5979c7c295bb049f2cfd3580e3da3841ddd8e6af" + + "4de5e6512ca79cebcab9280554524881da37984d340e8f0163fe10a02ed0" + + "88682560bc6d3c4dbcf1a542ffb3dcc2ed16a2eb96896e8269697ffeb50b" + + "73f2cc354092e782a0072fc12e1eaff117c2cc8a5a1ad8b47802ac9e23fb" + + "91a0cef9e4027595e0885464e61563093ee2b1dc5f22dfd04af7de6a70d5" + + "977d3751a4b3cc0c71a71c59c0534cb1f8c0eeddcf1c0e1b3e5ad0d083b6" + + "6e8b998ddf9ae9d3b365c851d42e995b9afdf8d66b2ac40bf514ce32e456" + + "0880afd38c42c08926067eb243c4b1184e667ba756c14ace5f525eb48df7" + + "ebb429d0a23d159664f8021d27dc7167081de331c7114c9c6456e1ffdb42" + + "2172a81c06d8deca995e158c48df27261a83f83e0127f5e056a139be9b76" + + "e25dadf534d3d1ed6ebc0b5d77d51e5b90ff86f30d4023066115bc11b33c" + + "c827b1103098826d0bf8777176b2da6f1e5b580e407ccf7e614fdf4f5b53" + + "3ef6d30b20c1bee61eab90e983b1a97173a62720ffd27abb8976a948d532" + + "d06596c23b0ef31c79831bead8f8e99ad209af3658cac0cb3c3f9c88379b" + + "9bc871d8e84171d53400902da1243f664afeaff60bd96ba2639a7644676c" + + "a79f43130af12ba2c877d67f7ec030a4217a72f5368af7c9f24e643db6ac" + + "97a04adaf57dbc53762d8dfa1afd49667c4041adcb5ec303e191b786273b" + + "bb065cd9f16a3a4a399c6a7aab9c1a6604998264e8b3dbd13d8f2228b13b" + + "2c2b9fec5055d8e9f2df1d9a25e4bfe2029776389877bbef7e2c7621f06b" + + "c0b7fc0786e2b2d042483ccd4a59d2872a6c5ac73e217123e5c8401580a8" + + "d967e0895aaa28f4d25ce68c90b4394d8113bc423e9fae46ac47bc2ac191" + + "fb97b80b5a85feb2bb54f84c493235c1408662fe253c6786fcf6fdb8be87" + + "dc66a72cc847f94dfb5214af5905b7039a7363a1b23a07853daa26862783" + + "ba08a80846fbb93ce98700a4f9961115128dd67bd7d19e0c588fdf6196c1" + + "1cb0154002ae862f11421f5dc3a57b6c0870b452272be556a1d14eab1af0" + + "a91ff5b89de6bbeed6e03bc64f5efddf9e54da71c594bc5ef78e0192cfde" + + "da36e4ad1a6b0b51110c1b24d20dea1f19e18cb1184d80189f842d4f07ac" + + "834744dd009aa3771b1e5502fe4b65a403a4bb319e1880ff6ba852e90a8f" + + "4fcb52cf374c88408428cdb1255291b04ed58c992310955198d61fa1fd9d" + + "762d48f2f65a287773efc67d549981c291b427889d3e3dfc0cc6cd68415c" + + "dbed81b516786dacf431472a7dfc99688d15bb6c1b85b1a2015a106e5de8" + + "cb9eec4c80b17d00fdcf4a9c64de4643a95dade8fa9f1bc5c839037d86c1" + + "3800a244188e3b18561a74912ed72f99f2365f0126732d037dd54a3ab77f" + + "9a9f6a1c1469ea92eb707482066bd4990dec4d7614ccb4ea6dd4deb8bee2" + + "2c4dc0b9b4d4cc70a500d2c8a5ac3ef88a38439b7dc254a6d920cfd317a8" + + "4d7747148c65b6730709e43369d4c995b03c58b9df444f77f216944e70f6" + + "6446554d8d513b8f7f28ef0a2d7ad5ca2f6110304196953247a7ac184f68" + + "61fba896c2d5a59007ec2b2c8e263957e54cdc1f3b4a145228823fdf0960" + + "c33a28f59b03ee4be21001d2f56fd49ed14db33b2c4eec2c3f41b250a624" + + "99a9b6602c1e838526a54cdcd058af1c252d56009d4c7769deace53bdb66" + + "543f5a081cdde775e61efa70956fe2a7a6019a164c6e413ded314bc928b4" + + "aebccb946ffdf3eb33e187bf421febe26112b3262a526de65678cd1fa03b" + + "83513705108fe0bb87aa99aceb28af3641c46a2c4427cc1063de01aedaea" + + "fba68155d4de494a27ff6b7fcc8f5c5c3f7d3a115c397a1a295bc55aec8f" + + "7f150cbce2a8aa4706d54ec863877bb966ad441c57e612a1b5d438b98d9e" + + "fcdfe6d4f66e885f96407e038015cf974ae5a3540692b054d2ddfde59b28" + + "ede7e2f581eeb56c5b88e2779aea60c1d8ca6107b0cdda1ac93e6c7520da" + + "edc66afeed12f980e20e1e1c327d15ade4bb90de30b011a9cb33855ca3ca" + + "e2", + }, + { + key: "2b0b0fd3347e73c2fa3a9234e2787e690a11aec97a1c6d555ff7b4047b36f372", + tag: "81b1a6633f849ab0aa7baafa58a5d9b8", + in: "427f3a7a5f1142ffa68e83df5f917e07b2bc454f3adce068a8ae9e0908e1" + + "3e0099aaa9074697593c6d8c2528fedddeca05e3888be1a0a201c389a72d" + + "20cb661017544d95a431e70e7c6580d8fb46ea4495bc59db6ae2cd69510a" + + "02426c50de1b6110120f759960605aca718d4d0a497e003e1ea2b8ae9a53" + + "df3c1eb4f704eb32f8f05eb08cecba0fd4a94f0daa3b0984c30a38f94b7a" + + "10cde723182d30588bc40f1f9d38a3bab4800fdd5148e34e396144763696" + + "c9b3e9b8adfdb337123d54237c7413f98bb2056152b256e37a27bb947c67" + + "240fa3ce8da62ab367db540bcdd9eb873d6c71c75a08fe99b5c11ec8e6af" + + "f926d2adfcf073479de394d4aac5fdc6241824d944b8773db604c59afc01" + + "495ee755905e5616f256c8a64321d743a1c9368d46418826d99b762e2f6b" + + "f998d37a995969cdc1de85f0ce3987c6550459f5e5bfd9173bfcb9e0112a" + + "d91f092de446beba14fb3b8ce3fb2f9c941815b2cb5a3b406e2d887b7912" + + "bba07c8dc7caab9836827da93ca71fa5ada810da1e5e9b09738524564d8c" + + "923746d19c78dc9107b9f20f653e05d7f2eb6bd90cf5eb30fdd7b587eb46" + + "74a1064c70ef0af2e75373044d32b78d96eb1db3112342d38dca0e47b96e" + + "9307fcdd711b1c66355186369a28481cb47ef6bf6651c2ff7ee4665247cb" + + "12b573933d3b626d1c6264c88bd77873c2e73e73ee649216bf0b6d6615ab" + + "245c43569d0b8096596f25ceca8667661de1cd60dd575697370ebd63f7e9" + + "5333e8a2cdb829b75ea83d72cd246d50358f7c094c8a515805fda03165d5" + + "21391617c9f9a2ea562b419632df611a67912d2b369e5e505dbd5c719253" + + "16d66cd608cc4a9583a8eaa4661b7279870345fac3031631c1a220551527" + + "5be7d8d89b71960e687aace3a0e8f206e475053d6fbf97717b154c75406f" + + "2caa97d1ab66048f1c99281c188a2f37b8bfc736c25840a9130ef2031c05" + + "6acd9dc10592eddf94f5bac85319b10ae46cc136a0738aa803837287ed7e" + + "dafe08d1fcf31d5e63763e39a5e1f4d7d0edab368d44e63fdb33c28905ff" + + "d6be406a024c017081b4f2d70860776e9d2556cd008fa5017b58733da13c" + + "634938407a118827a80baa28d4e605db59430f65862b90cd8356baa287b8" + + "4e6d9199fd80abb9fa697e2c2c4c760128e4ec0438388cf407e2a2fe0f57" + + "908187ed8efd4c5cb83cc91dbe6a11444eede85099149ca82921bc28bdd6" + + "b9999594a41d97307f8854b1bf77b697e8cdd4daead2aa49fbc571aa44c0" + + "bc84a57cb5fd85f06847ad897ceaf449eec45bddd4e4eb1e1e119d15d5e7" + + "90957e686acbdda1bbe47ea935ebc4b8c2e3cf9b7157cc6dc03bcb19508d" + + "a9e19cb76d166da55559ec7e0995d9b50c6c45932d5b46eee400c56d9dee" + + "618977dcf6f76e3e86bc5207493afbc2aae9f569ec9277f33d9f61c03d59" + + "dd6d8250ee8cb3e54e5e941afb74f0735c41d52ef967610c9f55b2b52868" + + "4b549a99ae3392a7237bb52ff5f8d97327e2837268e767bed0bea51f76bf" + + "88bf0286bf22b881f93f1d54fab5cd4e3c148c96c39e7aeef375de249df0" + + "4d89d1bd97a7afb2be0cbfd3380cb861d31e4ad1ea8627721e4518b9db3c" + + "cda20273ec23549c4adc3c027e3ac9558de2010a0263c1225a77dac8be60" + + "d498b913f91391d8b2656ffddb06e748cb454dc2b7226745f11030a6b9ae" + + "09ac8ac428d9c6500801fb540650c94610ab70465b1210c6db2064dc84dd" + + "7f52573f8f40c281470e85176c85ec6de3c718663d30ad6b3dfc1a3a9606" + + "1936744357ca62fb8bb066aa1fcac6d7a2adf0a635cd546bef39fbd3ee0a" + + "8802ab0466ec9b049b5892a9befa4377cd199a887c34569b6f90852139a7" + + "86babc0049ee2b527aa96b988237a52eae8b4b49d2ee15ee5294118cee62" + + "3c3e11cecb836b21af88555f10be2eff8379beb615b7b3d6c01d545cacf6" + + "61be8ebbf7a3c58ac5e0e7b17997659a2bf15f2b2e3d680d142fd29d23a7" + + "aea9890f3ff7c337fce49ecedaf38573edfae07810ba9806723e576d687e" + + "a11700b8ccb96a6559259c367cef4e3999a05a373ab00a5672ce8b3d1dec" + + "a414187f383e449d10021b73c1f7e39ce01516b7af96193f9993036049fc" + + "72ac059ef36b2bcfbe13acf140d41592880fb8294ebffb98eb428ce9e65e" + + "1094521bcf8ecd71b84c7064539a7a1aac1ad2a8a22558fb3febe8a44b87" + + "72fc00c735773d4ce2868a0b478ee574b4f2e2ceb189221d36780b66212c" + + "dd8fd3627cf2faaa23a3d0b3cd7779b4d2b7f5b01eb8f1d78f5b6549c32a" + + "cc27945b5209f2dc82979324aebb5a80ab8a3b02129d358a7a98003e701c" + + "788a64de89726da470010eda8fdcf3da58b020fadc8970fafb08a29bef20" + + "2bd0707e994015258b08958fc2af4c86c3a570443fe6e1d786d7617b0c66" + + "29a6d9a97740c487622b5b8186c529d7f8af04d9f0a9f883043f08103ca4" + + "d70057ee76639f3b1046d86928d54cd79fb5bb7b46defdf15d2f8578568f" + + "1d7b73e475e798ec6812586700e038ed4791b23ac9439d679a1a4bc04cea" + + "e328330c24b065c9cdcdcedfbaf58e5299779e6f48783d29ec3b1643bc8f" + + "1095c724dea75770583b15797fc666f787510d91e65a8e2090cc1ed2013f" + + "e63ab17bc7640ee817487f4eac8326e9c4698cb4df05d01bae8c0d00fc00" + + "08919484d5e386c8f60b8ac097c93c025d74faa56e8cb688d1f0c554fc95" + + "aae30873e09aae39b2b53b1fd330b8546e82d9e09bbb80132d794c46263f" + + "4fd7b45fda61f86576dec52c49f2373e4dca31f276d033e155bbcdda82af" + + "8f823948498f4949bf23a08f4c8ca5fcc8598b89c7691a13e5aba3299ee0" + + "0b479b031463a11b97a9d0ed3189d60a6b6c2390fa5c27ce27e28384e4fb" + + "04291b476f01689292ace4db14abcb22a1a37556675c3497ac08098dfd94" + + "d682401cabec239377dff592c91aca7eb86634e9d5a2848161dc9f8c0c3a" + + "f7b6a728371fac9be057107b32634478476a34cbc8b95f83e5b7c08d28f6" + + "fb793e557513ca4c5342b124ad7808c7de9ecd2ac22d35d6d3c9ce2f8418" + + "7f16103879ed1f4827d1537f7a92b5bbd7cd12d1ecc13b91b2257ad073b7" + + "a9b1ea8f56b781bea1bddf19b3d7b5973f1065fb72105bb4aeecca5b7513" + + "ffd44d62bf41751e58490f171eb9e9eb6d57ffebedd4f77dd32f4016b769" + + "fed08dd96929e8efb39774d3c694b0d30c58610541dcfab3c1cd34970195" + + "7bf50204acd498da7e83947815e40f42338204392563a7b9039c8583a4dc" + + "faba5eaf2d0c27ada3b357b4fccd1595b9de09c607ebf20c537eb5b214b8" + + "e358cd97992fa5487bc1572c8459c583116a71e87c45c0ba2ca801931a47" + + "a18ef0785ebbe420790a30278d2d0d42a0225d211900618438d1a0b2d5be" + + "d14f8b4be850dc8cb08d775a011683a69ee1970bb114d8d5017de492f672" + + "09062d9ba3616e256d24078536f30489e4dacd6429ed37aab9b73c53fdd8" + + "a8a7aff1b914b9d82d75a46d0ccf85f48d3ce9a8d3f959b596ae9994ac3e" + + "3b4af137d0c8e07ece1b21fd8aa05522ba98f85a7ab24ed8c1e265fadf4e" + + "9a18c5ab5684d8ba8d3382ad53b415c73ebfaba35abeebaf973b6f18e0d8" + + "7f019420eb34e09bbb12afc5b149f1e9e9b6ae36ebde429d437ada1a2d52" + + "b998f7c75ef731132aafc3bb106a2ad3ae11223a355804d4869ebaa47166" + + "2df261d95d48ac6eb17c1781e81c0027ccf8f05c39e1eda7793cb16622be" + + "ce7a1ad5d2f72f8bf4bdb2f4f4dcadac3db3bf727f0d447adddad4500360" + + "09ee011bf4155e5e46c74b00d72e8e6a88de9a81a5a4685651b90e874dfe" + + "eba41698c98370fd9e99619ce59ebb8342417d03fc724f9c910ae36ac5e5" + + "b46c424141073199aaac34232a8e17ebbfdd80eb75e82290de92968f3893" + + "0ab53dc83ac433833576e86fbabfb9d7cd792c7e062811f4cb017710f841" + + "1e0fb65ea4b3cd68b0af132cb08330aa13579196ec632091476f268b44ba" + + "8f2e64b482427dfc535d40d3f58b4dee99053b35a3fed1cb245c711fa16f" + + "c141974c8db04f4c525205dad6ca23ccaebde585cd3bc91f5874452ed473" + + "08de95cb6164102744f90b3007e511e091653c97d364fe0cbd7f4cd3249c" + + "1f5c452becd722ccc8c6b4e371e2631337dff78efd903a8fc195a90ca5a2" + + "aa4513bc63cd43794ff06c5337329055c43d4fb547e63d6e4d14fbe37b52" + + "1411caf2f1b0df51a68f677db59aa227c725cf494ccb7f8cacc5a06ac5bd" + + "f135a2603175a5fd5e5af615fd2e7cea61934e6d938b9e672290aaccd99a" + + "7e26dc55efe928e56ae6354168264e61668a61f842a581cd0c4b39e0e429" + + "04631c01320857b4d7e260a39c7fbed0593875b495a76aa782b51fee4f88" + + "84ca8ddb8dda560b695323cdde78f82dd85757cadea12ef7cf205138c7ba" + + "db6a7361a8d7868c7aefa7aaf15f212f5f5ab090fd40113e5e3ad1ab04f9" + + "b7f68a12ad0c6db642d4efb3d9f54070cc80d05842272991bcdae54cd484" + + "9a017d2879fd2f6d6ebce27469dda28ad5c345c7f3c9738038667cc9a5bf" + + "97f8f3bc", + }, + { + key: "aa3a83a6843cec16ab9a02db3725654cb177e55ec9c0c4abd03ada0fbafca99a", + tag: "719dbe5a028d634398ce98e6702a164b", + in: "643883153c215352a4ff2bb2d6c857bafa6444f910653cacd2bbdb50ffdb" + + "cae23cc297a66e3afefbd85ab885e8ccf8d8f4930e403662fb4db5121aca" + + "82dfcc3069bd5f90be4f5bfd3c10f8038272021f155e5de0a381d1716abe" + + "0b64b6d0f73c30baf6ddfe0e6a700483cad0fa14f637afb2f72361e84915" + + "78ba117e1c03f01fd61aa8f31da6464f3d0c529524d12dc53b68f4d4b326" + + "db7fc45c63f75244002b8f9a185556f8aab85948647818f1486d32c73614" + + "b8c4763e2645bdb457721ff3901327588da01622a37ccbbd0374fec6fd1b" + + "cce62157e64c4cde22c3a5f14c54cd6db63db0bd77e14579989f1dd46461" + + "4c8691ef26406984b3f794bb7b612e8b160374be11586ec91e3dbb3d2ccc" + + "dbfd9c4b52f0069df27f04853e7cc8b2e382323345b82ce19473c30296cc" + + "453f479af9a09ec759597337221e37e395b5ef958d91767eeb2df37069a4" + + "f3a530399961b6bf01a88ce9dfcc21c573e899b7951723d76d3993666b7e" + + "24dc2570afe738cbe215272ccedb9d752e1a2da00d76adb4bc0bd05b52c3" + + "fa08445671c7c99981a1b535582e9b3228ce61662a1d90a9c79afbdcfcd4" + + "74def2b7880cac6533ba0a73fa0ba595e81fd9a72ec26965acc0f4159ba5" + + "08cd42553c23540bc582e6e9ac996a95a63309f3fa012eac14128818a377" + + "4d39936338827bbaafad7316e500a89ed0df7af81be99e2f6aae6bb62568" + + "1dfa7e100ebca5c8d70f67be3c1e534f25446738d990ee821c195c98d19c" + + "fd901e7722b4e388da90b95ac0b5b5dc5d052ad6b54f6ea34a824bcf0cd8" + + "7f1fc9a07e8f5b8aa0793e3c9c1022109a7c7ae97ee2a2867fd0cf0f8971" + + "34b3d150d3b24fcf8323de929b73cca01244df02510393f0b3905caa0268" + + "7fe35f64391e7d4b30be1cc98319716528ca4f35bb75d7e55cf7749968c5" + + "37136eddb149a9f91c456fde51937c0f35e7e524647311077e6fbe7f3c12" + + "37b9584fcf3b0f78744c7b2d3b452823aca06d144e4463eb5b01014201cc" + + "bfed1adf3414427072135d48e705b1b36ab602cae69428e7c19d39cbb4e0" + + "ca26a871d607ed4daa158b5c58a0a9f4aa935c18a66bdeff42f3dc44166b" + + "a299d71a2141877f23213b11c52d068b5afadc1fad76387cf1e76571e334" + + "0b066ade8da02fe3b0bdc575b1d9ec5d5f5a5f78599f14b62db0bef7ccc6" + + "1711482dfa4787957d42a58fdc2f99525c32962b06492229399980601bd2" + + "ee252306b1464914424de9aa414a0a6e5dadf8ffbf789e6d18a761035d3e" + + "f2ff0753becbd2dd19fc1c28f9acebec86f934f20b608a9ef735ac91f6b7" + + "83d9327cce7f4870d39bbbfb0100838dee83e6baf2b40cfc98415dd174ed" + + "72e393ad0459e8035dce7eb18eb3af2f39d2712846b9e1852cd61d06dfc3" + + "5e34fb761b67e2a711ceb4a82557371ed32ca8db2e4cd7fea0b6bd026177" + + "4057b9abc45dae6869cab1097459473a389a80a4523e5de696554f8b0bec" + + "0ca605e6acfaa00386fb5a48e0f5893860a29f35e680be979cf3bf81ee7e" + + "ed88262dc80af042b8cfe6359cf8b475560bb704728034e2bd67e590bd76" + + "1632e516e3292b564c7265d7a6dc15c75ba6f6a447b1c98c25315ac7de59" + + "9edc4993e4dc7d1dbfcea7e50ebd0b226e096500216c42de3abe352e5b09" + + "a3c9754aa35d00883906599c90a80284d172a90abbeaf7e156fe2166ada1" + + "794420fe55b1a166d752d0eb7f04e822d021c615e84777101e7c9f9dd12e" + + "565b7d093fe978f85e6142c1ca26798b45f4b8d23ecff6be836e810e314f" + + "ebd2ea66f2ac95bad84b39b7a6bac41448f237b45e9ec579235ba2bf5fa1" + + "f00286379ec107c743f06ae0d11b57a2f5b32e3bc5f1697aae812d7ca303" + + "b196a8a43259257f7697bae67adc7f121be561b2d0725982532ffc06cb22" + + "839d9066dce0e4d683d9348899089f6732de62751ca77f1c439e43054468" + + "2c531b9c61977bc221b66030f7571dfb3ddfb91d9838529dbc99612f650a" + + "d72bb78de061192068941a81d6ac341101aeb745b61bd7a87a35a2714d50" + + "c3eb2c3ea148fb9ebed948307f8b491aec277ac01903ba36e6ad54f89fe4" + + "280a17f8e7ae639e75aec16d56576f03c2a1efe4af995eb825ccaa6efe0f" + + "d6d878299a351591d791c286cac5cb049834580d47a9bb7720d0603e3141" + + "ad7c1ec2dd23d3002e15d73c1828a7f08062848b1b6fcf816bd954743547" + + "6f0d6f882125bd03095eb1b1a846d535730e258fc279f7095de7c2d3fcca" + + "a4640a2e2d5ce0974c1e073c60bb78171c1c88ae62c7213a95d36ea9ab17" + + "59093813b85d17ff106e69100bd739ede9656388bf47cc52730766a8a186" + + "9dcc623e09e43cfba1f83ae1d9f16789064ec73504c29686760ea02c6634" + + "a929ca10c6d334b1751494c6d143671ce8e1e7dcc9bcda25af895a193032" + + "ce27c1016ccc4d85507fd2265ebf280d3419f54f66ba2a161c068491578f" + + "be056f02f97be745db443e25ed2647c5348f278f4ad8bf5b2a2c2d56e795" + + "532e25585984a3a94f435ef2742a0413abed7230ff2e9724187c91f73a7a" + + "726ebf36bc8d0d959418dd586452664990889358c56720c1001c004ff768" + + "54b9850890ce1b31735fd9f4a3640622ef0b25c659e8a937daa0df7a21f1" + + "77be13dfdb8f729da1f48e39a05f592d8c98da416b022fd8edab8e6132eb" + + "a80c00501f5cc1e0243b6b096c8dbe7f8c6ffa2f8bcc7f309fb80b489b92" + + "c4878fabad42d91876e10ee64ccd415124461cdc7d86c7bb6bcd9133f3c0" + + "dfa8f629ddb43ab914c0ac5ecddf4398052229876fd838b9ae72523946cb" + + "bba0906a6b3ef26672c78cb24cbf691a5ec869d9fc912009d840772b7da0" + + "c7f47856037c7608705cd533918c207a744f75fdfac618a6981778e09332" + + "5c7d22170da85bdc61044b4c397919d601a30746cefefa798c58f02cb827" + + "0d130c813cbeb67b77fe67da37a1b04bf3f1e9ee95b104939220fb8a0394" + + "86ab8954b2a1468016f546406d1946d531966eadce8af3e02a1f59043ff6" + + "e1efc237dbf4dfd482c876531d131c9b120af8b8fd9662cef1a47a32da40" + + "da96c57dc4efad707a4e86d0b84262d850b451bda48e630c482ef7ede5bd" + + "c55147f69e2ff8d49262d9fe66368d1e38ecdb5c1d4e4042effff0670e69" + + "04e47d7d3047a971d65372126ff5d0426d82b12b253bb4b55005e7a22de5" + + "6fa54f1dfcce30b1e4b4f12b1e3c0de27cea30ce79b08c8c1aceb1ffa285" + + "c317d203a9f2e01d542874fc8035b7670f3648eec79561d6ff2fc20d114f" + + "ba4fbed462f1cd975ee78763c41663849b44cb2827ee875e500b445193e1" + + "4556bcccfaba833bb4ea331d24a6a3bd8ec09906c7b75598b44ce1820a49" + + "fca4a0c1501e6c67515d4fa7f88f6aa3cd7fbc6802131a7b14b219e154db" + + "9ed241133e10ace40e4d963f904dd9f3bdaaade99f19de1ddfe8af2b3cc4" + + "0a48374dd8eb559782bea5410f8f9a1cd128523c0157b6baad9ea331c273" + + "311492fa65c032d0d3b513d23b13b86201840d51759021e4133f873f2781" + + "8f54f34ba73b4f33107d49c8de1533856ec37bb440f3c67d42148765610c" + + "3296bce932c839fd866bec3762a38406ac2b39d0d93730d0c88cb8f765dc" + + "d8ee71263fc96068b538da06fc49e25dbeaa10a5111a9af8e8f8d78e6ed1" + + "3752ad021d9f2c6b5ff18a859fee9651d23a7237bd5a5c29029db3882c47" + + "0470de59fd19fb3bfbd25d116f2f13ef5c534bf3a84284ae03e3cf9cf01d" + + "9e984af9a2e63de54e030857b1a071267cc33d22843b28b64b66e4e02803" + + "c6ab5635291aefa69cfeb3958c09d0b37176842b902da26caae3f0d305e7" + + "c6ab550414e862e1d13d9bb9dc6122cb90ddb1a7bc6d31c55f146659baa9" + + "6cca4ea283e5e1639967889543ecb6849e355b6c0227572097221dd46c1d" + + "f8600b230e9644ba611ba45cd83fa4ac7df647b3be57387b6db12682018a" + + "de9be50a8ea7d5f7c743bf0c6382964bb385b3c207c0cdd63279c16130b3" + + "73ba974125291673344b35c8ef9a33be5a8a394e28dc1448f54d46af675a" + + "edc88ce85a11ad7e50058df4f3f2364abd243683d58a2b13fcb0dc0eed21" + + "380b666eb87f4be75e7f2842bae916c15af3e9658c55408537b2301faa6e" + + "42af4d94e3eda6a41d6d302be281e2a9299e9d0fb1f20cf4ca978e66bdd7" + + "4c8bea0f15c84d6513cdea787dacbd4bb529ed03528284cb12f6ecd841d3" + + "c58c3a57c6bc19b65d6d10692f4e1ad63b091137c8acacc6bc1496953f81" + + "2972bf6362cf883bb75a2d10614029596bf9f35e92addbb50315b30161b7" + + "de8867a1393d9583887a292cadceb54078c9c846ec30882e6ff987494060" + + "721d3c761940b91a126e8d1e0118617bdae01a7f9c1aa96bdd6c78ca06f2" + + "6c8d85664a8705334f4997c724ef98fe265985593d5a9c30798714e6de1e" + + "bd04b648be47a6b5d986a3103e738a5cd114b19b7ba99d2e2eec6181bf3d" + + "ff0fec8c54ae6118be8702c3e775d493a6fafb509712a43ee66c3f4b75b0" + + "194c88937cffa5fa17b284d2556f2b0eebf876e05f92c065515198bd5e83" + + "00d0db432cb256a4a0f9963a05694ffce3ecbd182209e0b7bb50120f6be4" + + "eeb9d268b17790ee14a2c887dc5753e0086630b3123734053aa37595aa8f" + + "31968ddae4991af4ab970c1e3cfa1146a2efd9dc42abd6af14777b8a0455" + + "3865691cbac4b4417b3fa13c154d581b498f3b8cb77adf0e42dc2f2fb521" + + "732447de97271e542c6cf8cad3ba0148cc3ba1f2983ead836a25a2c022d0" + + "43ba18fcd009d518d07b53344a5bc4d626b3b38405a114471f75dc70e015" + + "d11e8f6f57d087fa72909785573008b1", + }, + { + key: "1793bfda9c8666f0839b4b983776735a927bdaa3da99b13c9f3d1cc57d4d6b03", + tag: "bc89cfec34ab2f4f2d5308b8c1a5e70a", + in: "a09f661aa125471417d88912f0a4a14115df9a3a19c1de184878291acb0e" + + "89ee1f9d8213f62df442f8969a9a5a7c402fea09bdbe236fb832544e1f93" + + "9cdd4873802b2bb8fc35ba06b7ff96da6dc7efddfeeda84116bc525a7fc5" + + "2d84d2e63cbac00b122dc64f2d15b36595259d81a1d2a09f204c54072751" + + "dd812259df1104bb2d2ee58baee917c5d0aa2649c8a1503114501e6ed6fe" + + "239847d3d88dccd63d5f842426b600079c6bf06e80a2813b2208181163b8" + + "61dca07fa4d88254e84dac1c78c38397a016b5ad55a6b58878f99036db56" + + "89871ab3c321f6ed5895f218f8fd976c348b3f1269fcdf4d38c9492b4721" + + "6c45f499f5705830b33114d721f9731acf6c69fca681b74c2d82c92e145b" + + "7bab77110821d3a12cc818d7595a5c60c4b5e5219376c38a4dd52d435d41" + + "562802ff65ba2bba5c331c333d5adf194d29b2cd9ebb55927bb4ec17681a" + + "3f5574ad34fb4e964f2c756f6dbbb7a6876a21579a515263444de7a30a33" + + "15005458bc137ccfdff18a3892fc9f58f1de10d4de20bbcf860f5f036d8e" + + "8a188f18e5cf7ea3cd260710e7491befcb131d49a28dfb1ef688fd021a1e" + + "e4420d32fbfb03b47f5e85c37d91e49a1b0db85d966eb5434c4197433eb4" + + "9d56f2ff999c9a72230447032dc949202468261b48b6ac212e3f651d6c63" + + "03a06c90bb2d3a755ed91ba73bcdc28e1c5b0936e51e0a9f69c3ebabd3db" + + "add7abab6d8f6a44daeb3126429a01815f57444fb7022a4a510f8b564ae2" + + "dd9779b3a273fef15859a33e233724846c30d89fb78a595b6ff6c834812c" + + "00a991e405806aafd0c26a788895ad00a5e43c5426197aa8247207077548" + + "ee67db4cd6f878431a2e36e952d84b5fb89d681f553198e2c066310ea6ac" + + "3a31f5b1792620616f6c41d486fb844eeacc7fd36971abf416e8d6d50985" + + "c83cc92ea46ac37da8f0026aba30c945d8bb15080d2d95e4081bad626199" + + "3f95f57ed3252822a7caa035ae22a36c35e280cbbc82d729346cacdb1794" + + "ae9a9bb2793fd1d5c47121b135c2836063367339c5151b4e35278e97f62a" + + "fdd2f231d4b47812d083a829ebb9c374ff2ae8479cc4b76d55f9cef3ec6c" + + "4894f53e8caaeb0d8cd072960cedaf758e48e3640590d4f728626e0a08ee" + + "ebf719c96bf8ed4d0c283be09c0ae67b609e22d3b9aa6b03642854909de0" + + "5ed52b39673867bf586a632ab8072de15c637cc212cba8387515c9c9c433" + + "abd7ba6b02abd09da06a34694ad34f88515b65c0c9c247fdf9819fb05a1a" + + "ea4728c1182f8a08a64b7581cd0fb2131265edcb3d4874b009aede0e87ed" + + "463a2e4392aefd55e008eb7ba931788262f56e53193122a3555d4c08133b" + + "66020154b15643fa7f4f5e9f17621d350ede3dc70be02c59e40fea74dbbd" + + "7919d1a8d4e22ef07c916fa65e7d4b89fb11a7c24ddc4ca5f43344c753b6" + + "1331c3fa4558738ba7832b5b2a275bc9b7989b6e6888865793329806cd3b" + + "f0ba57c941d4428623e062f4ac05e7cd79ad5446f8838f2b247b66bddadf" + + "540845a1bb304a04b7edbbff579c8d37e2f6718f8690abd5231822c7e565" + + "69365ce532449a41ae963ec23a2a75e88307dc6b59cbb3fab913e43ed74d" + + "841ca9f6e4ef96dfd9f04e29e89361aece439c0b2e1943b30410a63d495c" + + "522ac3ec1b04ec4cb345f7f86969957ad750e5bd7dbf1d6a22eed02f70b8" + + "1cb5b2b020c0694d7f63044f9de0c3de1ede52009c858992d01ebb92ff19" + + "a9e0fbea18942fbafb77746c8e9e687dd58ccc569e767528bde43b62c7c1" + + "270a5721f1212de2b29a7aae2d6ba6cd173d7fbc78aec4356ce2e8ba9164" + + "d97dec061dd0c3a0e3c520a7611ac99739049dd5825537c70b7ef660046c" + + "1785546cd99aa400da848eb7c3c91247415c8e245d0f14c30d482c5849ae" + + "aaeab2568288229b08267818dae8f76fc674c684c99eb5faf88a0783813d" + + "f7298e0b50cb233f78471e5ca9cc3b04927c26a3871cf253798cc49aa717" + + "d8f18a1ddcbdc26497d188f15f86ec494dcf8f942c3e07e572385c6fa0ef" + + "40c0b625f1737543074a747a369482a0b342a08b3eccac9f9209be31aefe" + + "5a7794974f71ac0bc9a58026397ea3dd4f5e40511d58d2a3b45925c194ef" + + "13987037d736dd48b509d003a86471d5f161e0e5dd168b4f1ce32f703b89" + + "15004d8dfc708a5bb02b2e6fb67424b2cbcb31ddaa0114c4016b0917382d" + + "aad11815ff5b6e37d5af48daa5ef67cee3439283712bc51b5adf2356cb2a" + + "5181b8941fd78945c7c9d61497683e44fee456ad345e12b4258f15945d45" + + "b6ca4369ee792d849112d583fdb39cd4d333ee057355f0abc8d1eea4640c" + + "128cc1617982db0394233dbd416102eec1874081247d2982bbf9fed1b1b3" + + "8f4da923d68c8975c698f189a4d7840fd7aca9dceb7d91c076f85e1c546f" + + "4d5de4f60c91348455aaea30cac134c844dad93d583c139dd52b3be6346c" + + "4d2e6864125c5a2d0aed8f67930e1ebf8700ca88aacc914ea76ff17148f0" + + "777738cc126e75a2c81110faf02fefc47c91edbab7814599000ce55fe20e" + + "f313566e9b62457acf2f22e1141e220bd9d4747417d03e703d4e39282803" + + "386327fc65dd597f723ee28185c78d9195fc70a75706c36287ab9c6e00e8" + + "5cecbbd6043c6af8d30df6cdd8777be0686853b7c8a55a5b1e03e4431d39" + + "1725ff99875a85cae6926998723b36d13ad458220712209bfc5e8d2ca5d4" + + "4ea044d5ba846b4035e7ac7e9885f55d3f85c0c1b3d09fe929a74450f5d2" + + "9c9672e42d3f59be4ca9d864a4322cc454c2578493bd498a51bbe960e657" + + "3e5dd02c4a3a386d4f29e4578a39e9184024cd28d0e86ecac893b8e271bf" + + "ce3f944d130817378c74d471bd20a4086f2429ed66c5c99969fd8da358ff" + + "5c3be72bf356ae49a385aa0a631b588ddb63628fd162673e915cfc4de56e" + + "ae6ff7101df3b33125c9bab95928f6e61c60039b6cc07a66f9c733251447" + + "ef9c1ffefa2158a8ddf89dc08686a4cf9b86ea09914e79842d72a3236afc" + + "98a3afa0a1cac5590ab6a923e35a2ab8db6410a9d33cb84d1c48a054377e" + + "549774b25f50fbb343ecd5db095155cce9fb0c77d09752f62d4bbf16a770" + + "30452a75f6bdf73f7807d8f3a6bae16ad06b22175fee60549c22548de9c1" + + "3df35ef4e7bf7b66491a62b93c2c3fb0c5edc51f60f5704b56af30f1079d" + + "7c385b99f958ef8209e030e381d1ee8d67d3cb84f32e030e8ea2c1d0c77f" + + "d6b242a9f48707557c8682a08e1127f51221a55c733ab1edd00a9c2912cb" + + "36dde85f73b524e1a4f4da6414c5e4c18d9537722b2becc8a91bcc63f2b0" + + "9f32409c53c2beee0de6726dabcd6bf33118a5c23fb9c5c1810476efe658" + + "4bb6109c516b45e16b2f79f96755680374d82b91f2c519639a1815fd485b" + + "a3c00b46fbefeafcf25554ec5a6a5ae2da07c85b8a0f9fcde50263d9ed85" + + "038b2f7aadb9de765655bd201235218bfc74bcad6a9ddf4506167a649afa" + + "df400b85752d68a92b7a97f26b334dd77fce824862046b286a7c8e0adc36" + + "f713a252a673d4d995b268badf4bec8b8eefe85c25b823b6728582d35c4a" + + "60041114dab72b0623b99e2758f6a1e97365279bfba0eb1fc8952ca4f2c6" + + "fbffd9f5fd7dcad1125b18a796981b5ead0b6431141315898ace96f0d38f" + + "865698df8822ca7b65644b6b1f0a0f0d2e5850d4c93ec48ca3eba1b919e2" + + "4413a46d595ffa427715e499db3b7b9ab53c64abec7302bc737a5bd124bc" + + "da756abbca132f7f67e6989e09bfb23b497da31bf156bb9c69ae54588df1" + + "7420e8fe989f0472c8893b2bfe57cdae265a8cc7aeb39624167a567a6fbe" + + "bb1aa30c3dcfd14f2808a070994085e6e1fa79021e77c399f90ab1f995a7" + + "baff672cb693bd39b798b4c890b7d0a57978d6b9bcdc5bf3f4d205f8f24b" + + "2b43d3ae300a96971c9182be297618b9adceebedba1ab0f324b01d23d7e6" + + "35f009db3dbbc643c2d787567594bc639bfd78c4f3e6d948caf06f013423" + + "eb3c764666b58f886d5d28137c053c2a28535efcea400147e92ac6753574" + + "3b47f9cb48852abed1d057647d5b1c6f334eab1a813401fccd3dae332738" + + "776bb223e359f3c459b5c573ba64fa945bdd66c5ac0fcbd53b67032a7b80" + + "25f551e8d1fd2a4291bdb7941cbabe3a09765dc263e2bbb6db7077cc8fe6" + + "790d4bed5e36bd976d1e37dfdba36aafcdaa10c5f3ed51ba973379bcb8fd" + + "203d8b7282abbd271ecf947e54486e8653b7712c9df996a8ad035f41f29c" + + "ab81509f922c67dacb03f25f8f120cb1365ab3c1c286849c2722448ba9bc" + + "ff42a6b8a7a52f2c79b2bfcbdd22ef8a5651c18879a9575dac35f57d8107" + + "d6bece37b15d7dfff480c01f4461ef11f22228792accda4f7936d29d4c56" + + "cbba103b6d3e6db86e39e5f1bb9e9fd955df65b8a6e44a148620f02b5b90" + + "b2be9e5bb526d0ec75b1e723e94da933a356d7ca42d0ce8349699f730b8e" + + "59bac24a6b633759c88041d29399ce60a2ca2261c7eec1acb9a56e0e65bd" + + "e37653ce2cf7eb83a4d019c755bdc5d685b6394ecddb9006823182dd8138" + + "a1bf79a32d07a8e5e8ab221995c714e571b40bb255b79e328ab883542c16" + + "4899fffa16eb3296f310e302512352a864fd809beaab4169113027c6ccca" + + "99a92c6ce35c30f9449a3add70f10db1ed08078e8e6cbaafef630aab7e9f" + + "c8adb09c18e33fe1af3620d1e4d069ac11325e23cc18e5519a1ed249caf8" + + "ddba871c701f1287cc160019766988f63e089bd9bf1af7e6f5b9002e3b6c" + + "264d69a8bac16914ab55c418d3a8e974677cdcbea36c912e90386a839a37" + + "77b878e680c07c7cc99f42a7dd71924babf7fb0627d1f2cc60d9d390d1e1" + + "50d47386be6eefec9ddbb83b28fa7e2fd28cc3867cbe42d13b00545af8a0" + + "48cc07016ec79808b180e0b258c564739185da754f2e", + }, + { + key: "0d41cb4ac25217feb20e86fc2490e8d2ea2e8225c051252a9395cc4f56e1ae5a", + tag: "42df9f9a59d6dc05c98fd9e9577f7176", + in: "01caba7a19cdb09dc0ec6c522c61c628eacf17ef15485aa5710fed723875" + + "2e4e8e93dd4bbc414e4c5620bab596876dfbea33987e568ddabf7814b318" + + "8210a5f8d70041351e4d8410840642a29cc8d901c25fa67cc8f9664ea5e1" + + "9e433eaff7c722d0258ae112b7aca47120aa8af4420d4412a10732551db2" + + "cd3e0af6e5855d5eea61035af15a4d0d898d04033809e995706eba750a7c" + + "ac07aaa0dc71477d3020f778d0347f1a8e37c18540deb9ae967e734c0264" + + "df0e1f52b0b5334805579ea744c8784c3ae0c3ff8217cd3f53cb747f6996" + + "f3d2147699799e649061b205f97f7992e147fb20f21ff862c6c512e95534" + + "f03075e8e52f162e0d70d7a259e3618474427f400f44f75198edebae6e40" + + "a2173257d114e1bb5a13cf419c821eb124d90e89a938d91f4d2e70dfd1ab" + + "60446f1b602614930a329e98a0c30f107d342281db25b8f8259933e14d20" + + "8bbd991e42969e8b0600272f9bd408483cddfc4cb8dfe7bc19be1989c7fa" + + "129d38e1078d094b82e0a845040ddd69f220dc4aa2b236c44101d7da7779" + + "9827a7b037561b51e50fa033a045571c7267af93b96192df3bf6180c9a30" + + "7e8c8f2b1d6b9391767369625015da02730ad6070df4595eb8099bd8e484" + + "59214310cb62c3a91a4fa8ac3b3d7b2017d4254fb465f0a248e1bf45819b" + + "4f0360f37c9a79d405e2bb72e5c25a1b4df192cfd524d61e1e8b274f2fe0" + + "634c73f0653c7c9e9062c9d081f22a8b0327897eed7c6e870f2815bbac8f" + + "585c1bd868759a98dcb5c3db2f6c53244b9cc494a56f28a9ba673167cea8" + + "b799f37049ee7b0772972b3a6603f0b80eddb58ef03f916106814d72f000" + + "250b3573c97c5c105910d79b2f85ad9d56002a76a1f43d9d1c244ef56d3e" + + "032a9bab95fe3bd5dd830ad7d7e341f28b58c0440658f7fc2ca98f157708" + + "1c647e91432cb0739d9acdbf973ceb9b0047634d695279e8837b04dc5357" + + "f013fde3c55c9c53bf1d817ec59a1b18ed0ac0081ed9bbb3bcd1a5d3634f" + + "50f7506f79dc6a4ebfa640bf65682fe9aeca68088e276937669250064de1" + + "c19ad6d5c697f862114d0f81d2cc52be831ed20d3aab1e41fe6f476b5392" + + "af4799392464c51394c2d1a8325ee2e84f1635d295ee663490e538eb338c" + + "7126a8e731ad5c0becf144c7a9cae5c6493350b589385de29e1a0ad6716c" + + "346ec4f0a31ca5ea35c59ab6b099f65d7f0b3d00925a1da1b5777c029aea" + + "9679e895d7100645dc83f81d82a6174beab2357f7888ea640900cf3ee67a" + + "e0724a123919d78e70e05288f67e5e69ffa6f345be8a96e58bbe260184b5" + + "ec5c0c1354cfd516ebdb8d420029137d41b029641959cc07fa7b4e16b39d" + + "17f36b2367057410a42e0550e9ec1dcd2df4604d52d4f9dd1140d57af08d" + + "50e1527dad793b6d649324de799754f755818bf10e6d1ab614958dbb24ac" + + "8e2c01270a90ec3df4379c3f509b5ef721b0fd4f91a1bdb8127ae4dc74d0" + + "75f6cd8bb28319d6f8e8d8ff64fb4a42d646e9365156c6bc72cc46e9cd1c" + + "f9e735549e3df9a8e6b5fe541948b126190117db71fd1d61ad84be0f725f" + + "20b99eb141b240326d399976c4f2ce5823d94649a9580e1e8820bf49184d" + + "fc34378a60bea89b12aca69cb996c17847b7fb517cf2d51f16d78e3875ce" + + "aa33be15f6a154004f0e1134c6652c815c705efc34bcf35bd7743d28f0a2" + + "77d82dea4709dab41fbfb4e0cbc118c17aa00808872f0edc6437c357cd31" + + "74a02aee61890464e03e9458853189431bf5df6a0ad5d69951e24be7f266" + + "5bb3c904aa03f799fe7edc7bc6779d621cab7e520b5994f81505d0f01e55" + + "96e14b4c1efdf3e8aadee866c5337c1e50066b3acc039c84567b29b7d957" + + "683cadfb04fb35402acaba631e46ca83dbdd8adf28e377ec147e4d555a21" + + "e6d779d7c5a3078ab72702234d36ca65f68bd01221c9411f68f32e16ef04" + + "99a20c2d945fa31b79d9965853d38ada9d48eead9084d868c6bad974b0f4" + + "0956aa0fcbce6dac905858e46c4b62c0ee576b8db7d484a524e951f4c179" + + "decfc7d6f619e86dee808f246dd71c7e0b51d28bc958110d122fa2717148" + + "77823242711632f6e1c7c15248655ced8e451a107707cec8c84929beece4" + + "efe5503d3c1763d0ab7f139f043e26027d5e52a00d5414dd98a324a8fc2a" + + "06a1345cbde747f41099c3377b86bbdc5a17c8f6e5b773a761f78573832e" + + "4359b143810361dedc79142fffc49ddc0b32f225d50d360ceec3920fb0ba" + + "0693b644ee07fbd1ce829e223a02794b197614061c4bfa46112d105c2b7b" + + "4efea448501d146dece44f6640d674d5749db498b32969de6e165e705a18" + + "2aa1f3d8e16892b0120337640d52c9bee35e5b4b17f03eaeb31205c8ecbe" + + "1ae1b110023016e40ee87370a65c5c20bfb00f100d3c6c1de6e4a1c90162" + + "f25bddbf300ed637330206788a4ff96903f971c9618493ad074412af625c" + + "ff9e0f8f183bbd5e96c1f28307e6cae8b50cc0eb1a3a8154e44e9de947af" + + "002e4d1098d6b0ee3f2e71a10d03eb444729c42461283f37be8af2ce81ba" + + "bac246a05c2c94efacc43f0cf9ff3df38ab6fc1648c796ae7026ea95752e" + + "b70873a6da59da10d8b5316126431c4a17289466e95dc739c061d7a4b13a" + + "450809479eef421bddcdade77a6df133410328c754af8999a09b1a5c056b" + + "ecbb6fc2c339586ab92100f46d2fa1fa689994b36aa70703d76bf7738adc" + + "f0589fdfa6bd215339ad69ed983f62efce0add5a63fe7dfe4bfa006ff16e" + + "0cc06d39199ad60adcae12b75ca98d764502a783373da3a41281e03c2037" + + "e1b3ca7f7eb60e2b67427e97ec72d36670db7662c6daa505701fd279f116" + + "ac0ef569471f204e1531c25a4ac3ce19b6f68a8994b6f89b5abf034a6507" + + "32c7fad4206eb4eaa7cd9a710d866bf3c3f13c16faa268ae0cf4f69be909" + + "bb9b79aab80dd25101d4cc813a48d3f38d870f10ac0b6768005aa0e69e87" + + "dfc0424deef06414c9ba6f498c93c41c692a7a6221fb5595b390a32c70e0" + + "2cd64471c797ee8a143725849c1e054ee2043dcfc0b4cb1c00be21a14be9" + + "2d9a07f1b4e975d4c86b8a5c1387e6c42bf393e078fe86d24612d497e14b" + + "874485a3cc922b5b6d91295d7b79ab8bfa1c7f64b51e761d19bb9da82a5a" + + "a34aa469699036b6b2c55e2b84f84942f10585027ab07e2e0e562e0fc3dd" + + "36047850ded84be4416e22aa41c7a2f7d4a4d8e3dd420d746a1d8d56d87e" + + "5133a1b4380bd9a89500fd6d7e68a1ec02eb9e79e4a13edfdde1273466e4" + + "6b0e6a75f59ff6175716629da52463ad21de27f40fa2e25a566eec4b2696" + + "4af3a717dfb0170a73144c0bd9b00bed67ad8c0a146eb5a055812d071209" + + "c9d530cd4f50a41488c2238898dea8bb36b0f1496d3ea8c4ff8e263b367f" + + "64977679e697d88e5295bd97ac16a0420850d1ead9621e25a3f58925c266" + + "ef5246488b1c15a8fe0d8ec4291864faa5a67b2388b7786f47b6d27e8fe8" + + "46f85f85163e54155ef95cea4901e712a44404a4d3f27f28dd961ce36b84" + + "f3856770f07f20a2ebd34d77405beab04ddfc09770167d7d6340f494dc6b" + + "7e4c3df896bd974730193b1e862b58d4a5938e6e4ae8897dba8812924379" + + "e54f51a71364d39f76e24fdf2c6c704479ce85b456558ca6947b8fd76f03" + + "78273f0a7bcd1d860ef1defe4eea8fdb81c73eda028d82fdcb2248582ac4" + + "59eb7698a811e6c5823be886410f6b8577ff2e8252343b6ea890016ae846" + + "01c5894cfb988121059fd9c8fbc1596da470a149404fc67baa15383d38cb" + + "d17ac107b4ff3c1ca4c76b7930de02b240e7547d39f4978e0cc1fa37f8c1" + + "012b677f07bb4df4486196e9b0beb823a3827585475b878e3f6f0a2d3836" + + "2c7d34f9f3c91ed46c39cec95c2a0b6f0279a03a00ed5035b0725c393849" + + "cdb1ed3c0ecbcf3c2ce108017f468e1c3d469c03e8231d4195344ced70cf" + + "daa667252cc1554dce8d0c54eb4cf4da62367d77d7dcc02f81e788ce9f8d" + + "d306ba1b48192359cfe92bdbea9980f87ea0677d7d2082205a436cf514e6" + + "fde5eadd21b13dc836ce33b5dfb6118bcac79ae00fbb16d61f00a923b145" + + "f9caa9f3a2c7f0104f8b052e390987e57c8dc80cd5f0358afb0111af1fc4" + + "e31f92bd832ad35fd2e0bdf768272de52ce0b152f74d43a8973ad516b3ea" + + "f5937ec8a236ebc86adeba610de0cf7168453111f3c983b64df07678cae0" + + "a75466ae15adfb127328e716448cdbd2c1b73424cc29d93df11a765441e0" + + "0eeed72228e1099bd20569d9d0e9e5a0b3c11d0002e2896631186483db61" + + "c1a0cb407951f9b1ea6d3ebc79b37afb5a7037e957985e4955979b91fb85" + + "61ca7d5e8b9cdd5b7ce0130a880d9241027b011fea7696b0c695d4949ca2" + + "d0cf22d44b9fee073ecaef66d4981e172e03ea71a6edc7144393bfea5071" + + "2afac137f091bae2f5700bfb073a6d57fddcba674a899d7349044a10aadb" + + "2e7f547887dd2f765f394de5dc9ef5dbf1eab4d869be8cb68aad8e2614ac" + + "37bbf21ccd5a832ee09fdd07ce50a580a2af36256b1046e646fe3dff6d20" + + "0c5110f1ad1311bc39b8114cd11ecdb87f94df43d4f6468932fc0ed892d0" + + "3d8f3db3f8323ebb29776ab7d260493a36700bcda668abd62126a8189e91" + + "df2d2970ef688d4e8172fc942e69ba63941a36b79ac546fff38f5f7d1176" + + "57612a662ea38134e1090c3e903c9adacdeefd3ac2a0467e9f5125058c19" + + "7b2260d2afad2b0e627a9ae52cd579ee27168065658089e1b83a2d8cdb47" + + "e08966e4ec0018e78c4d267f9575b8fea2a42de5c2d25356fe4b8c9cb1ac" + + "daf0d1af4bf58b9704cd4bc08471e3b9a0e45a5693433ede2eb1374bce44" + + "1f1811cdc7612d7bb61f4f34aea0a44757bbcc12a55c1ba41a7901eb004e" + + "689587a38e5b4df4574ddcc7b2eda97f6e480d7d39f45247ea3b03c90a93" + + "0dd168b65d52a59ce9c2cb4e860cc6aaa0ee02a58d0c8ba990194bce80fe" + + "8c34ba5693fb0943ec2cbfc919e534cc47c04f502b6c217c2f860d1d482a" + + "a016aa02adfc2bea3171fc4e27e2a262fd37b824099aa227fccca508f778" + + "b8c6ec7aaff1d15f6497753f439daa9e52060fd6e9e056e6843d770fb057" + + "6d9e2e782db4843c0c2c7f408a17376719a3c5cf9fa08f04f8a779885a16" + + "5cf93ce404be", + }, + { + key: "ddbd5d6c5ebd61fa72b453dd849dc302c98a0f3e300f4768bf1dc698a3827dd2", + tag: "af608b71a353e63c64911558baa122f3", + in: "c67e2524b0de16483158a0232078fadcf611e4fbdb9e642e397b21222423" + + "cc2ed42ed34ffcb178448919ee337eff9d7d691f622e70fd3317cfd271df" + + "fe6a9d9b7e07db0d20813e2331164a654386db2ab06ae2983bf2460eaaa6" + + "3aa0171fb87afb82e85b40d95c8993b2039d32e9d38473dd13f41fb1ff1e" + + "261752ab004b221a4472b9b1a0e139f0c999f826a26a7e7df362b0611aac" + + "fa83c55cca2f7c0138d2c30313c2f6eb357278328ea6ebd6a5077947e18a" + + "a97c34b9dde3b6f2de4b83778ffcebc8c9cb58756691d5e2a3d15a759a2e" + + "5050b6da937a6f5551aec069a08027d60dd870d175d2a5b5f0b4f3143904" + + "7445c368a5c866370e9426abbc1a1c5a272b96731c4128aedeee93e8e00b" + + "b450601a6d31ea279b9450e738b4a47c0dc22d2d8ed5d44257f6318e0c59" + + "b951fb6b57746062ab95cd73c23ef0a5c000a7d14c18bfff172e59b6f6de" + + "aa61b81009e803eb05e24fb0b706870e18889a9180ac16a042d12dfff9d9" + + "1b88130f045d2342fd5ddc5f443681c31090459f262d1a65654c55251fc7" + + "d5a67bd2e62940ccd606f3e50700e4d1e992a3fdf0388b9ce3df9de6dda1" + + "5c1cd6b70622ac062dcb7ed7058872c00ff3df94032853927126cf6fa4cd" + + "c468d91c9b52dcbc272fd7ba920dcd3ea1e048af9c3286dba74d988ce9ce" + + "77174e25a87935352721dc23b60a9549322fadbe6a00dd1197dfa25b33fd" + + "9e5713afcfd0fae6dbcf27147fa58d995580d7e0a903c895752fe9819f5b" + + "b002ed752719552d0f3575312f2e618173a8ae7c147ca64a709053e5d2e1" + + "2f4d1ea337afa9ac4f9ba62760046ec1e48f4ed8f6df66786c9fd9f5bc7f" + + "9ca2526e1327b042f4657c405757690e190c91f260dee2dd3d2e6616b721" + + "e489c7c3cb828478a3d953b88f09904e7927cdf6dbd6a5419eeeb83c0be2" + + "51934a80dfe61e09442f0761aa2d013e10aeec3a32df204571ce8984a430" + + "9bbe30ccc91977790bf0305d2651ee450b749c3e7761534e45970e70a0a8" + + "473cadbc88f096970c275f188c9d2644e237fd50c2e24c1eabbf7578e80e" + + "6500762ac513fcd68cf6f8bb7a9d9eedadca059d9ecec07fe6fe7792b468" + + "9311861728dd482f087c28374cf9c5ea20b2c8630029e8485fa6fe518c74" + + "ef77d44eb7526ca764e50b5f34ed0f253a91fb2af6e59338e2af6e041e01" + + "084e1efade1aebb7d1b698ccdb8b4248ac89cd40d9517d840960c08f5e86" + + "88d8ba2b54889c1870d315498b70e0e9720f2c8c53a3377a8c0bd2d6a1c6" + + "f17c6ff847eb14def6855dc3886b99039e528b421ccbf6064e39263f8f3d" + + "340d5d20b1b14c264ac2310b5f3a0c6f0c1006d0d4f1a69af68d28ab447f" + + "cd17387e1fc98f164982a6d05dd32d6b4f0f1b04e40c6c6e0fb4467dd6b1" + + "0c5a9c92cc8c2bc97ef669b6d55cdd0aa8a15c46af954359165949012713" + + "4ea9f74181d54a300d3172c9f01db73288ef6a709c763a4891666d0baf88" + + "8531dcc77f0911412d096aef9033fa36b5c1ed283b8b5c109e45b5cde911" + + "6f3da2533fa0ab81929bd5783271d5501a9e4fce2aff9eb5a70a4215b253" + + "46885d7e4225fe34bb55b309a114a312693d60ccc61267359a8c2dd28141" + + "226e7cfd99f0f12c69df57d75dd790dbabfe3145f7fd1a24fa58e03bc2e2" + + "6ea19288af4929e5acc517d8f52a074745ff4644d94179eae6ba7d267292" + + "bbd2053167a0da9be5e4b6cd0a4200fcac5182d9957dffbefa857e662b82" + + "fc3a7cc32506e78030ed5c5d448d7f1b4fd854a735a0c50016bb85e6e716" + + "0f87527bca0de235f4b7dacb75be84919c15a5b8cf6bec035795cb67061b" + + "7855c2134c1b1bfa6affe04b7db239f73af6ea9c02bc9f7972b7f6400b6b" + + "838f4653aefc42179c21765e3ca7a5e96b4402ff544d4bc2332756a23500" + + "11241dc42ec6848afe127c00b9c333e69bb5a54ea5c7193e59ea22bd6d32" + + "af4f56b1bd2d5982ef7d9c1b02d7668525e4e81b68a400f7afc2653f0f41" + + "a03e11c7a02bd094830093481afbab96397245b9f37a568ea1c4ae248cdf" + + "afc87f88b1fb5dc300d8e9039af4e6e701b458ed3f32d693f2e869b76bb5" + + "1358cbbe5b5089013bf452734388a176cccfc1ae9b7cff603631ca48e129" + + "b5c9573d4e379547272cce8aeeeb407d3fc57f782a0eb5fcbd41e6fb13be" + + "7e4f1067cd407b42a6121b2969c384916ba2b32563e659f52aae09c8ce2e" + + "3c500fbb7e58be74cc1592dcfacd9f0d4cea1a90a18658147c81cccf6fb3" + + "078ed27f369e7646f551386a74e1b07074d93e0c1f298c761af46cdaae9f" + + "f4be86808b66d0e228016d27a3a77c843365cb847fddccb0bbcfb3b9008a" + + "1bacac59ffb0aa759a0568c72c556caf0ac1091431b574687c5fc7bd486e" + + "963e0fc3bdc828d988734a21070747c955cf8dba2df1c3a0ba8146cd58b5" + + "91b6d54712db67a9851b1607c8445bc97406eeb7488f5f85e547850d619c" + + "407f97632ca1801f52c09c2b314b4ab0f8e7fb5851fd60852f4666913ca6" + + "bc840c1ec8f8f06caefdbfbf02ce00f20b87b14ba9e651c80f40a31d0306" + + "403f541776075fbf23733a6b19e3b44d04b455b29ef8effa70cce0c59331" + + "7119abc07aa8c8d0246a760b0b36a3d87b244e83bae8a745b8277a531298" + + "f5d0283498a509c89898ddf0f7a7455be1f8a6889c46d323f1dd18c3babe" + + "1751a05f871f0639f50967afa46c19cb93d9c2a79c81e2436a7a62f225bc" + + "37c90698640f5b43673e1dc276de05ff1e29acdb4ace5121659db5f23c49" + + "57aae22f53e6f2cc935824fbd07c2ac87672eeeab895c3f06e09e178560e" + + "2fcfa7097f10201dfb8b1ebac08ca806c1b3ba3aff9284846a1a3beada53" + + "e9f7ade12eb89b5591f462b2543bb4090e081fee9fb53bbf821dc92d6b16" + + "fe820ab2ee4b1f6c0b6a6f19edb0bf6479e257fc73bcd60dc2261d0a4752" + + "e23a0be18abf355f3065177d8c3c14e21edc178d0abd1b39f703e6335131" + + "ec90cba3d9846cee7354a06c320a3f61b8a269abc7138831614f57ca6c19" + + "a4a621142889cd924bf4ffb82b57f871b854f3157e8874c22d43a5726900" + + "bafbb8f2260a1eba3a462e23d4def2ccf68ebaae8e52739a1ce67c039eaf" + + "9a6c3232fbb5a91d1e59a8dcd3798ba71345fbf83d09b83b41cc49d5ff5f" + + "2e809d2b1d5fbc1e7001ea76b9b2d8f896eb6609e2e1c5c562d2a6e74960" + + "2d67a0f6b43a201d5087509b8dc7b0440144e308c18ff8b96b607de2f20c" + + "6ee99bb05367a8b25947011889f724965a2b5c52c9db1e0622df9343c548" + + "d054699badeb15fc41055af0d79a2bfc1a5b4574634fa0dd9dd10a6213ed" + + "b6991187dc560facdc27440456a0a209fd7f5ee4fb350ae71f869723e5eb" + + "5338e3d1448bc993afca6957f4cc7b047a2c7c9593b7234725e66cc0eb23" + + "3824eb4cb905701cc522ec210950b871397c6c0bb3d0b839f2eb1a120f70" + + "36107246df4dfb2c24891bef0bd1dc131f2c9d7c295ee967e3184d963037" + + "fcc9e0b8c7011c8e04b4e70038150d34caab4f8c0230418cd2d8a91146e4" + + "4e11cf6707452ddc03d9b4e6380658135dfb48f62c0690ebad75167f4dd1" + + "c0df3ed555b5081a7b82616d9e501757c83c2193d0f640236d59f9c97a4a" + + "5c8bf532aea2cf5964ed2dbd8a70c01ca5c7677224cf2a37f3b24d8fe4ba" + + "91cd3b5033715de227de51deed15afb8eda9d2b9615d197b8f98322d7096" + + "79c5131eed48050fbe0145a9284e236605c25a4876e2adba42f4e35a8949" + + "3d59bbf44b3338d9d2e65a7d7ec6c863cd47cae9e23181b07298078a5e9b" + + "06a5c7e1059f474eb1a4247e8f02cdd4efdca67d22035b12abecf9b15982" + + "de4932a28e797bc4de38442cff2cba263eeddba0ab14fc706dbca04eaca1" + + "b4cc13000a10e35b32461424809b299798e4d8e66c92aa3181c5df16ab65" + + "9611cb625e895a8021af8c60960227d6f2ebeacb17b13536a5ff139734ef" + + "37cb67018ef9a410b856e6f6eddbe3f59b088d538c50a8f3f0912d06e47b" + + "88d773069aa759cc614e1f53cf6e572c127123d1ab56b79ee753a921cb22" + + "a60e4e6cae768c9966de4e2625484f2e990154da7fca84b6e6c0b59201e7" + + "fb8a729cb20b4c774381e84f1bd6e304543d952dc76ef741b72f3a4ca7a6" + + "ea7958b8b6337994ed82dcf988eb70f509610b9a279ab4d0f28cc2b2dd99" + + "3b8637a6be0cb4b5f67c79654c6b15e1b61120374ba9b974a628c547f11e" + + "52d72d39f8f9c5dbfc23a89f22d38984dd8d5c3ca72cd54e6adfe2b3d163" + + "86afdb50967846a4c311351a51e5fd322757bdb061d44c8796a61fa4db36" + + "793bc11984eac83bbcefb40d0bc7bab0ca81e7df3a7f58c6fe800396716d" + + "832acaddff6d72c8e19dc9ea838294ead800deadb6bc18d3e399fa76c46c" + + "5d88ee72a86a87399423b0578eb6e27d78156ea2abf6f08b5cbf747f2f74" + + "5301b694bfba84bfe3c5527acd50660eea5105a2644c1aa92f954a604fb6" + + "a1b3b2d0331497deafc3aaadc7040b9188a36cf607ee85a0655ae963fd32" + + "91dd58f8bb50b4e46dcf7c2957639bffa6b12d895660dc0323b7a092f999" + + "813380b820e1873c60d3e3038129c66d507862100a5d5842150869e7873d" + + "6bb6ad022350ffa3813aca26c80ccae72692bed9c77c9d4da23178c57153" + + "90b5f4505240a796ec9d10a7f280bd60a570b1b693453807707651fc0464" + + "03e4768965a6f42f112152942134f0a38c84137c7a6e086ef1ab9ad20d24" + + "3b93356b305c0996ab7d02c02c44cbaf8f7e60b8c0b8c9fece3f189b099d" + + "dbd126b7357c1c4ea1c8bc1ad93db91ea9bf043a4320acb60b502bec37b8" + + "6b2a5004b8225e549e613c6f83b97b7e4aeda1b013e0a442d7ce2f14e78e" + + "a94bab700c9ac0abba945e28f39fdadff223c4498cb204f01ddfcb450a41" + + "f32ae47f99a49114c6646a5cb103e9cd75f9d81dba417e48c4053e3b0295" + + "2267cd30589b0f5d993a5485a6ead1ffab9f2f4294c5853ba76383a326a6" + + "a42fb8b78948aa49f0f1f614bd0a3fbd2a58a3197daf2094605bd838285a" + + "1260f1265dca74aadd95652632335fd17cafcb73b202c3f0e5da836c2dcf" + + "2934f005935dca80154af43fa34c8ba440d1581b74ff17dfaca369dc9aa6" + + "734c03916d78e1b952691cef918fe033d33f7f4323cf724ffb8cd6c219bd" + + "046e9f268eb0601098e93daa59dde370e46269dd7c54891f71bee2829a53" + + "df86a2c7fb1046cd7c98fa21cd83597be554997a70acebe0b6e60f1f7098" + + "6f65adcae24385cb7102bdd3e01300ffd15d00f9764b3a5c51e35e5c9cdd" + + "da84f4b656fe514ec4ff8dcd774373f8a9103cf36abefe875f7084b9bbd9" + + "42e0c997ec2d860a4b622ff1a39a628582fd81f237d3d8f6843d26ac77cf" + + "bd48003e8e8c591ff813a9a897e3149ff0297ff476299d717e54d885cdd4" + + "4c3ba6ebf54bc7a1", + }, + { + key: "b15578da1020f662ada0ad4f33a180d9f8ad4991b3720bc42a22b52625c7414a", + tag: "b0e4ad4a010afd6dd41ed82868cda555", + in: "6d2afb7a9154064341bdbb533f11990d4987e7c90fbfc0167c1e58d6efff" + + "6010f7ed569dac62ad37183b0d384519ebed0bf9c6e05a070b4858e6b846" + + "547ab5e45619c866f83cce83dcdab6a8a6c36b115ac832de1c6d433b94fa" + + "35803fa1a36f1ee114f8632402a027a74ac110394f32ec4006beb0057f09" + + "a94dada8bd0d1ca9a14b1f2efb8f526d79d6438bbbaac0ca1a43935627e5" + + "d129d52c06bf6413af07513bc579447eccc3a9406645c94dae59dab98d6a" + + "f92fa90fd4efaaa4bec466806ed401d2083cda587139ad7e9ee2adbb1dfe" + + "a88b59dd788b954a0f52c3854a3fffecb4bea83debbb2f5f8883e6415d3b" + + "ac1b872df1afe185468adc59364c173082f1dd6da9d348f5f5ba2d216243" + + "23de1f623eeec875bf31d12acec40dc0c1b9562826f3105cdad4c43cf45d" + + "829aa8b14012c47847aef7a2a6e3935fd972235f5d3a7ce4ad3582785393" + + "602e2e27329914021eff38ed2926c88acec1551f17a1b818fc1c3ed4b3b6" + + "6825d55bea269d710123b52e12ca9520a069d9c6a21df3a0253b3a4a6a8c" + + "dc226d667541548834da6bdbbdc165f39e40047d4b647c507d981be17b3a" + + "836063436241a8bb46b11a2867b621413c42d838e4578b72cc1982e34bde" + + "c303b5575ef4b8dd9fea8ed5bf69539413909d03461d3853b5fbf714a61c" + + "769569f42b38fac4b849104e2f2ac1dad0e388646278789f83e0b0511571" + + "019d3bfc5b03ca4cb5564e4e75e103ea1b6000be6588e27105d7cdc2d2f1" + + "f680ad34ef823ac4bd4068146e9997834665aec7dcc7a82ff28d85d52dd6" + + "9c18dd35f326bcf709f74df5981bb90ca8e765fef9f0698a19e12220b287" + + "24a6d9e4f4c7ce93f8ca9a126689ad1df820072557ce3db246cdf41599dd" + + "44ca841bece6c7869358005536e1189aa86b764e890ef90970d6e3831def" + + "fa890bf8692381123924e7d9df804fd770a0a30ee97d5dcdca302833efe8" + + "1d4b2505b17382f0b3429b38c41269ac95e36e9f5a1dbc6e6c8963741917" + + "02a23198decb4efe6809fcbeb5d0c9098a4c300155dc841610e55c8a6e27" + + "2a38a39de3d8ebf38a750af25836ffb1bb7822bb98886280f0cab6838c01" + + "cec57961bdc2e1bf158248309ff9294adcb962252b1c24646d132a3be2c9" + + "1ff82e8e101facbdb807826cc9d1840a90874ba08692e808c336c9d280ee" + + "f36a43a75c746fb864f85711e802546ab5cc3f8f117904ba1a85d6e4b729" + + "85122c5041891e16d55b93d6fc1b7fcfdc80ed3d72d55d64b8895bbf2f8e" + + "d188684e7e89afdc1e6a7ab9bd1d3da95d68698df2cdcbb2e1a4ae70e2fd" + + "dd4760f9e5cf4255eeb1e9e8009ab507395bacb8b2177e7c5757ad02baa9" + + "a96db967d20a150d2dd7f3081d90675fe0c82f94aa3cfdf6ac5585583901" + + "7a8e122170cc817f327a3c8ef44acd6e4fa81b73bcd0bcb5792eed470481" + + "152e87f7a20c3f7c69d5a8199bf9bb7c7269b450dc37a9b22102acaa8438" + + "134d6d733d231cee9522f7d02fbb37b5818ad3ca72df4752230ee11392ef" + + "8f8219be55202bc3d476f5a9078b32fb63d42bed4cda5ef90cc62467bf5e" + + "418ecd9d5d0cf1a33eb9a930e652ce96057fef40b65588aac67621d651a0" + + "9003dbc3925912e385296cd3b2b386a44113308ddf2af52ca390487eb20c" + + "716b76d78ad45129e7c285d918de7107ea8c3b0cfd9e73933b87c0b2b505" + + "cb4c95794f2ee6d6d43e2e76026923a0bbfbc3bb22df9ad729452283ce62" + + "dc9b26684fd45e07650581afd73713a708869a069c58b599ab478974f206" + + "dbd3e4e563e346ff1881723c5fd440bdf9f70f761c6f746113397d7c04b6" + + "b341d7e44de7de0aae79badaaef5ed372ef629dffd52926110683ab2d4da" + + "a4be83eb86c8700703a660edd5a5029f66f1581da96fe1feefc970ab4086" + + "a83ae02e959821967bd27b3b629652f5bc3db2b7f1af674f9f3fb3a788f7" + + "88e6dc1722382971831a7ed72502f85b25888c1534d81c0a4f7351ecc40f" + + "4e0412e05718403fae5746d313a78c80ac297f1391ad389070410e1330a1" + + "b07d683d1c795bda74bde947f2cf0dc9638b5d0851cda27df030403816dd" + + "3b70f042888c9c192656cc4b9fea10b81b5347900d9199c8f0f47d42f2ee" + + "482b68acfa5ff47d9950c950a926a497d94c6a796e0b715416520bd6c59f" + + "30217718d5f1d7bf7c24039f6467214ac8783cf011b25c37c67dfddde426" + + "40afe97f94879f4586954737b86701b32d560f08caec3fc45184bc719c7c" + + "5bf699074fde814acae32c189158c737665a8f94637068322f0c23ff8860" + + "f1b1c1bd766440afee290aa6f7150c7adefa6d72a738cd2268da7c94788e" + + "bb39002e9a328a51f3a92dc5c7cd9e4faed5702d3592ad16217c4978f84e" + + "af0fd2c9e4c6f4dcdd9112c781eb41a9aacb0f7935bb5c92d41e67cfff6b" + + "991ccefbd667ffeded1de325da50c33e28e2eef2f636c9726dc5bfe753ee" + + "c7bb6e1f080c89451f81bc8c29dc9067ce83deed02769714fa9bb477aca5" + + "c09089934674a0cc8e4b2c3136b2e4af8040cc601b90a4dec898dc922ca4" + + "976ab5ae4ac5af93fa5b1854a76ac3bcc2090bdeaa49ec4f319cf7c7b674" + + "6d8e617abb3361b28b27983dd1b139ec4f5af7e116439d7ecb16534817bf" + + "264dbd8f59e80b443be12c17fa013c7f4d029504c9bb62b296c2326f4f49" + + "cc3201b70ac3f62abb683c630179594a6d4cf30fd55b163bf8d01986bb6b" + + "cb7050fd527f095c45661920268e56f760fee80a29c9d37b7fc23f608710" + + "1e723038e64ee1b91c4849d69bd95fc9bc24fc4a234f4855f2a203e3f699" + + "c32698585c83781677739f2c48697c93b3388dcc64aa61f01118495ded33" + + "21ef9a1c949481f96005f8d5b277a7d6a0d906ec304cf4292df172e72d20" + + "29ecdeb65f06267a605f376804bf7bc5b82d5c8facfe7e41dc10806d27e0" + + "bcc5a341d80b3c1532407f75088716d732632cd88b0037f0d829bf385fec" + + "b52a202956489f61f16b0f4781bf59068b33d7330571d0b4a6ed91830258" + + "e1220b308784fa155be9bc821f5c0009a33802fa66dd66d1dde997dddd97" + + "873ddf65927dc1be979af2b5f110eee627dc1e210326ac20544a757ac168" + + "1823f3dd04b1ddc4bf96677a0a87633994e7af2ec99b7d5dfe44c6192be6" + + "a6e69d17b074256da3947808fbf68c7506a7e2c99e6b64d1ffadbd6285d8" + + "e7e032e24d42dde0594bf03fd550be05e5d66c91a660cd1ab7cb1f43fa9d" + + "69885203a7aee35a28f117427d7ac02b742f53d13b818f8631081b1730d1" + + "5b4e1e283cc8e5c4fc3b4652fce05fd8db821f99fcf93e6842816a549791" + + "7f6c49cc53d733788b2fe3c687de58bfe6153c70d99380df1fd566a7c758" + + "8052c62e73340d6a9eccd2ed26b763d518f3a0c4d6362212fbecebb4ffb7" + + "dc94d29944fcc4ab37725b105aa7571f364146782356d8ef056a0be93a55" + + "0c890df8fecc178776fe40703ad1bd2443d92c420be4306d99686592c030" + + "fd3e2230c0b48d8db79002e8a832ef27edb53a45532955f1171203d38414" + + "b4692e901e9f40f918528fc494430f86cf967452f456b01846ac6a383fc0" + + "de2243c7d804e8643aabcb78e2653b145f400a999670217c8da43bbb9c11" + + "e074176424be0c116c304a420120138e901eca4b12ce68fec460b23bc0c7" + + "765a74fc66cbda0e503e7b1baf5883744e468c97c5f1c4b0acc4b87de9f1" + + "4b537405dfb28195439d1ff848d9cd28a8d375038ebb540a9075b7b5074b" + + "ebc18418a370f1d3ac5d68f5d239513002ad11bfc2b7ff53e2e41ccffc4b" + + "0503acc4967c93ae8590a43439b5e7987d10cb8d1957bd9ef717ee3d12df" + + "5d6736c1d8bd8da102337a94b7d14f830f6c403cbaf7925a8a2a7af1311c" + + "57224967a38f6ca374013a9819c55fd2e2a5fac4f2490be5b059f4cd9c60" + + "2d62f80789eb8d9ab893c7f44a4945e41886af218179dfa754bbb59aab68" + + "13b71d2202eb8fc8a425625d21176a28a620e21bb0dad820c0b7051ce8d1" + + "3a33f3af0958bb6cd89f9d6414ab00ddd1d2f9fdece9183d0c05fcdfd117" + + "10d250e4b2029e6992a88293d0457e73e5b1b6a1aae182c69b9cb664992f" + + "073595ef68117026ad7ea579a4043cda318931eee7b2946a34cdc7c9755f" + + "80cc79a2bfe3ed9c79dc52faa5126b824868c965eeb37e9e4e6a49600f3a" + + "cce93c0853b546edb310dcd16a5755f15b1098b2f59dbd2d90e2ea8360ba" + + "f12108236e854465456598ae2f7bc380f008f2e3cd7c98c87643cafd7c36" + + "d40e2597236428d46aa5b260f84b4212d5e26804086adcf00363ce4becb4" + + "9b57eb2847b2f18ec82c99714ad4ddfe4ff3bcac1d0fcaa32660a1dccc68" + + "5bed83254c8e2ea0ae3632a70cfbcbeadef922d78a006d43ac7ab1f8a609" + + "c6e0ebc3ca6bb8430f1a562f41010db74b9febf931ca794fa08d1bc17780" + + "532ae76f25c4ee679d788835dfa4e70ca154c9e2865c3750ffe7b837eed1" + + "972be058fdf2bdb3eb301867bb132306c7aa237f6771d60bbc56cf31cb30" + + "32a87204d454542de747418470025ab84935d3eaaca01dbbdae9ef6b5d3a" + + "ca62ce9f871a3e1272b2b671582c096a349c00f32d742ddb17993994d8ae" + + "fc178cbcf9abc03114ff2bf7db8f757c63d6898faccd822f5c2e9a7570fb" + + "9cfff148570888be24ae42644c1a5bebb6f6287147a4bcc01c7675be9e4a" + + "897519dd3132a7cc2e778f8c90d23dc8073f6fa108d7ef82d561794bd9d5" + + "f1faa306334f338ac3ba99c853f79c24f7048fa906fde87d1ed28a7b11c0" + + "66a3bb98f8d21055aaafdf7e069b77b60b3d5cbe7c5e4379c7651af955cd" + + "82a19a09caf36becb6cd3fe9e12f40379941542709991066df21b7b12dfb" + + "2416d83fcdc33bb583e3b42f24f53edf8dc7c579ad3be831c99f72bf9fb7" + + "a35b6562e824e039e6bf1adc8f5ca53846de7bae11c4317e696d887df33c" + + "525f0a9c01fc29f2c26c90b85fe82ed8bd50954cd4e9ac7c85c7f3efec75" + + "da1da4ed173cb695cee295190527edb3cb06c5dbdabe0228cc60b6455153" + + "76244f27aa56da2db10f2659090137ffb82c57233c833e0bbf22d6f647fb" + + "97b3652d2888b3ab08010b8e8a6967d560b747757806736dc98b78226634" + + "f1eecaa4a2e23ba36591acb5737d735c5bc7a2e36f1a46946927e061fdf7" + + "7a3b68ef582c26b01f5aa9a438ecc26c6941221d1590c838072f9e471fe7" + + "fd59dacb0d092d40d76ea2f7c6e954a132a015bd4cb31147f3ebe4518322" + + "916438a62836ac85a4cf4492190a85bcc8edb37e38b99ea552d749c30f74" + + "ca20c298165e8ed02d4671e0b41cac3a32a345b9349ad22c2a4bb2c16a4c" + + "e0613ca0f0518759f7d2b33cfad2fae764f410d4d9ff8a76ae02a8107e7e" + + "01d9cd0552676b85ba002f19c01ad5f416d1d08bb84fec7c3555b098dbce" + + "48e1a5d847895e54db9c5b80cc22d5b87cd41a1a94be102bdd45a3cda5d1" + + "181e10446d213d6b3fdc350d486d2011d705c5f16ccf7519065c47bad7d6" + + "89c71e5fdf9d04bfb91eb1f07fa0f001009c1d4b1f6a116a570823a8580b", + }, + { + key: "392468efccff36dade31fc1c62eb38bb61394fe448def9d9d9beec2413ddb418", + tag: "e1122e7c8e6965b90addbd46d8a548d6", + in: "6a13d37f0ec933194c227351f4a19b507d93465b1f3e88dcb5f1ed1262fa" + + "58ea99ff31e6fc85c39c04129fa69195b71b2060122fe618dd9430a63f97" + + "54b52a80b3cd099f248f91a468bae211a27bdb47ba005d29881ea5143a82" + + "967c4c30c9a4f0dba1a4975e6407fe296d40023a00efa06be763f2d73d46" + + "a2901ae28b3d8ce18009a462e223b71476d7b954c138e177d15a390847de" + + "96a7f7fd0598748e86b0f08e64d915e67c7e3cf936f3dcd60edebd36e2a1" + + "d65b6ac29530c48ab3bd52d45b4f938a19b9b31e2911105a8561600d5377" + + "905a67112ec28025aa680350ff85b808c5b4c98b7b9567d03f5ed3911ec9" + + "365a8de4b15ca62adaa69e5ba710eb1756a346016c67a297d8624f9f1ab5" + + "b3fbce98b141049f0ce26c85d2f8a9cc6ca8ab6c6e148be968931430dcc6" + + "2bf58ea9698ef52a5d271cf48e6748ac9e04bc7ae7da205a1a7535478322" + + "d820eca146cedf4b2f9aa9fcfd77ab56a7276977401dcc1f96baa1b607e0" + + "256bd04ec324ec67a4313e2d5a53d3a3fb5332927929b20c63bde805f637" + + "eb1050fee2a152a0405634f55c48a59fe370d54b2ab1671dae2c7fd92243" + + "10627808e553127c74f724362b4a6ee49b697daae7df3ddc5d2ed9d6befd" + + "77fb9f68fe3041f6ef13f46f34ab682ab8563e8996344f82b2ef006a8d54" + + "3dd9c1db4979d7da97bda45e722065f8a238f0873217b783a9a629a12b3a" + + "4de437445039997bd243efbf5e3b6059b9459d395290efb9081c632fb694" + + "81000dc74c395cb507422df181aba20f776ce3fd8765ac485021992c98b1" + + "67c68805662cb4356a0ee7ba6bdae51ac10cd06bb5b2f3a72841c714c8ed" + + "bc56998fe2fefb9bf69e172fdf54b2ab138ae59372c52a67e93882a3000f" + + "d966992aa2250c6ff93e9cac89645d70625d79332ade5dab7eb1adbe7dce" + + "5a013fb65ad32fe22ed16fb9bb35eca1f37a0433c320e8752f8fc4b7618c" + + "5e4df2efece832e259ad98b895c474e47d0e3fc488bea8f717a17de0dcf7" + + "597fb8fe12e62246296f9a887dcc3a700820c190a55a4931a7d44bd3bb2e" + + "ab6c8a8126f1be93790cebabc1d69e01796e6cc80e7c16bbc82fb333fb21" + + "c774ab7db843242838e82d8e1cb8ccab385e67a4271fe7031d74b6e8edcc" + + "8ed585d1c05a365c7665899c1dbc561151d3b44bceace77c4f53c0e0f6f7" + + "74d42f9ad3e56f1c2a8d53879d695f895690afb4698472a3d52d67159313" + + "133c87823fe0500eb68fe286f8b9a2f59f12785d026dc97bdbf793c7d1eb" + + "155f1f136aae66c256583e987f718afbe733e0a5ce30d021493fb84e2242" + + "5b18754d126235ef80335004fa84f88361a584753df409360cd8bd45bace" + + "8f48156bec66577bf2c685089f5ac7e7ec76c0df068fbaa47661f8517f92" + + "e14723b3b278f151816537a7212c96bd340a00c15c9c9bc9a2a5d163655d" + + "84b38073e2be9217cad97d362d89d4baf3ce0a8d8562f19a8c97a9aaf5e7" + + "77d60456360ffb77b30f177d2809052020d141697ecf9cb65f42b9190caf" + + "6540b2c82f6e5a8482934a6a1a5711a8c24546cd8ba432068404eae5a827" + + "2e09efc3c6037af4feaac0a46329229b010ecac6b9f077a9b076bb6d9ce1" + + "38401eb38d124baa11507a994185295020bf9b754fcf78430db9253f5929" + + "87c46c0f8589c4e463b15a3840b1cea795e24cf6b20f29a630136e0589b3" + + "8dd7fbe5ea21da72c88bd8e56473586822aa3765660a45a988df9b8eb8e8" + + "141939d3e4cc637c5d788064d40a9f7c734e43fdf8d7189a5d76700d9743" + + "fe0122944663afdb88c5201318ca782f6848b742ddebe7463fd4a32280ac" + + "1cf8311e9137d319de05ce9cd85abab24c5364041c14d3b4ce650400498e" + + "122166eccc12784b7ac3b262ac0b198ffc26eeed9a5da5374f7a2a53c87a" + + "78c217ea1fbf8d38f62511657b73109f31691aef14d82ce6e1010eae9e6f" + + "a419e5c1c16c0cc70651eb3374c03549a1bc7d3ed42d60f886102c798dbc" + + "ba56f0a2b3b9b412530c35f5f7ed06311ee14571f9c26ed9c81ef38ff000" + + "2f5ef3aab7351e32049a6ef8f48a43da1d84402d229df513dfaf1b2e4043" + + "6ce68c70ebeddd7477c9164f0dce45a6fc5de050f52ec269659d5854bcae" + + "f7762ed7400713c27a4d523eaf8c136c4a1ca00b9e9e55902daf6cdf8528" + + "c22ca1f2fa7ce87902d75a6850e1a5a4592497be1bb401878f18b189b0e2" + + "c59d10705bfabde3cd2da01eb452006b294108d5d42e88e9e15424d8cd0b" + + "8ab43a6c546b3dbf52e47b59cde6a3e417b0395220b6d63736d429da3458" + + "9a2524f1629320206fa7f1d8a041e17222c4a5814561937e1030e6375c77" + + "9dc988bb928bbdbe2c2eb20111639725d82b5d7192cd3e4acc27581f0ba7" + + "286cff41f97aa5a52ea0083de5057fd2ba985aa738e4d03fcf11ebab1d97" + + "e2ac77d1c2beb8799150a421a07b3777d0b850f24194b8309135b13da6c7" + + "e38653a711e407a1811290fbb7bc15d8b12efc6916e97ead41e042a44721" + + "e9cde3388073d921595bcddcac758dc675173f38242e65e4a284aaa7e8fa" + + "6adddaf00bc46428ab2d8601205b8895bcedfc80ca0aa4619ed6bb082ddf" + + "33ec04fa5d417f33fcdd238c6b11320c5a08f800e0f350b75d81e3bcbd15" + + "58a1eab87a3c8c2ffd7ba1d7e754e607cf98ba22a3fc766c45bd6f2569b4" + + "84639e6611714119d188a24a5e963089a16ed34e20b9f154cad8ac6031dd" + + "7a3a885afc2ae5e003ae8d4e4aabdb3e51dfc423b8cf4ed9ae2010072cbb" + + "b1108c7da1ff075e54ed827a0963ac5523ecdf3fc5eee7b4d1a6773764ec" + + "5c30f41690523fd70d895edb7ca6a1806d54240c4c7b43410da73503a323" + + "90d9070ed30da3a2fb5eccd40d083be7cf8bf40b4279f819cf795b6f075b" + + "5a67a10a06a6076d0d83c72efea05f244901c4b5fd9eb380432519311baf" + + "8c81f6325df4d37ff4d30d318f904ebb837ec76b341dd00a8f247cf0bbe9" + + "6f3784dc8f5feb344958fdf1a9ececb105f8770826db1f17a5281e997951" + + "d3c60cc28fc3e66ffeb5dbac315f98f6d240208043f28dee963d843e68ab" + + "57d847f76ae2f96ce6e37f377ef5dfef2176ecd7440ce4dadcec2231b606" + + "e4a80420fb3ed135640e1f05d6bd58b8dce062dd7d36b885d424f6318e5e" + + "a0753efbb33bbc7360d2b5dfab3ae0d5e000b8d31f2ba0f5fd8b34f96b55" + + "28fff35e769461d0f03cf3bfdf0b801dcbbf2838180cb9b108e06c353e3f" + + "0b9ef61678cfed1ea37ae76bccb5ef5957ac2c8e8f4794c8145a15f1cc88" + + "bfb0881080326c481b373c3bc9b07a9b60a0c8bd5fa4f6f90145590a5227" + + "6fcc0ccc2375d0ccb571d414d1b0c38b4e02c39db4d701c5e25e90785ef4" + + "d26f35edd8c4b96455bdca7245cfefd9cfbd2f319615e5fdf07bb9564fa0" + + "44bb35a58391d02e3927780b4076bc0893dfcb4b63a32cd7a541a4a8c253" + + "0349c6e96e378dbeb66dedf87d813d0b744452c1c4088507dca722193827" + + "9e2dfa24e4a409de494acf654f44262db9206a7717fa434ac4fdc6a6eb5b" + + "1fd5a193b6043bc4327c8c09fd6822eaa9df37bbcac1077754a295621601" + + "267b68733b62dadc2563f1700af180141f29899e2689dbbe9745ba8477f4" + + "352921900b403a01c9dd042a8c1b0e0489959fb0b0a8431c97b41e202204" + + "212ebfa00c593399dbd14d7aec07b8292d2e40b48f05fcd54a15da4a24d7" + + "2759e409f4c7b5b98fce4abac6c30e4872d92efa1f96479ec30f21699825" + + "50fa60584f5a09051a00f8e7dbb3853e66ca3f05fbfe43bef9b120a25a01" + + "eb436ba8ecda715201eda72e517d628f883386c1503aa8b8e75610f7155e" + + "9f916335ab6d6f0f9589b6220cd2b81c2c937dc065d3d14a7df8cc916cd0" + + "0ce1bb53fd9c8974298d3bd316f3658aa8cc6904f073a1472149e4b08c64" + + "5e11abe0428ccb6174df2103edd735965d6454b543d3f01410f77053f65e" + + "c1d1aee56fdd3af23bcd4e1a7fcc4e600c4831007c33fe5f0c8300f686eb" + + "9b4d1e4f08fe4ddc8a90be14dc3a5a88ff96716509341d5db24c0d016863" + + "998b1859c5021df815a6f1ca9845f1a8e99dbad132b406227c5897a1bdf3" + + "e698962f799133ff4429decbef6ce036296facf38e4812fec102b76c6d30" + + "beba1b70722254fafbc471096153478c971db7d96263660209265cb10f13" + + "b34b5fd55c4abe818a5f9715d8a85094e2946b7a001b47f629e26c636d86" + + "4968ad2ab616dfe28840bd60b4b9855c8dbe1cb873fcbc4577b5fefeb8bb" + + "4832039867dc35db9c036c83bc204396e3474ddfe806c77c65c936f488b6" + + "7c1028739562d7bb055d21441af29ae2921290e548dccf8a56021385422b" + + "15da6b232b24151309a75a00296d11aa1952a1513110b0faa93d1d8cd9ae" + + "fa9f1c59377ec9165b2c9e07cbde40db7b81bca6d58fc28bae8f473cd0e9" + + "a2420e0b943a83d284108626c24ac570b1d6c1ab971e71f43fbd6c00e171" + + "238141a6dc987a60385c3a04dd147a2f8e80dfe727b104c0fdd80b326f59" + + "0b9f86fd7b2fd1122a390979889eabd803ab57159c8509a1443eb6789382" + + "090a770ae4eba03306f96e50e19a7d44c584ccc230d104548946efca4520" + + "d61de5f473e2f4eada6c8ce9c7ee975eb4f63c0483cb775ed7d3cf690a61" + + "7d6656d683a8512707d81ca5ba176a42bcffcfa692129f292607d2a47536" + + "ccaeb464c9272d6f3816074b712af602470088b253deba18771e5f67734b" + + "587707cdd06f35264b2262fd253c25b5d38ee7db287610e5398062b7a34e" + + "6e4cf7447d00873b930ad148fd96f0ab18771bc468b874bb109924101c84" + + "c4e239ecc7687d875e4d94a1a973620ca61e35a872c2e2e61a502169f1bb" + + "4e5ff5fa2bff657be6195b3e2c7151a52fc0096d98e7f08f5a98f570aee1" + + "7b4275f1356e87e080ce0e1b9bbabe7dea48b5903bc390ce23472ad64a89" + + "41c3247bfd23ea90b2dee09085571bad85568040105e098f993bb37e43c3" + + "e6d511171c77cfc450570dfb9fc6a3930ef43c03f8213f6203d545d791c7" + + "d3fa42d5dde1655038d35c5dfacc12e9dee24fe833977549eda68ae8b508" + + "be277e743921b584f9dfa0eefbd8bf3c23f51efdef7f7487001d29e8097b" + + "ba63289cfca743023d1668555a46fe6d5b7421377414df1e9ef135480622" + + "22e2e9a7baa618d88f407517f6317b6a0ba3384ace16d68631d59ea169d5" + + "092d20afc1a481b82be5e734bb092953a0a94702bae1a0f48d2a22b9a05f" + + "f64493b7b2e984f27582b1eb937fddf8512c49830435d146dcc291a4118d" + + "5dc638b99cdcbcc5860de7a92c5b13cbd1e01e051f01af40afe124346320" + + "d3626bf9d8f7850744e032a993c276fd388718237740c6caf260fca60b8d" + + "d846102e3262b6e05ceca00c6affe938fac1847350865fc858d3ddd1d130" + + "71d1221ce7c5d575587fcba580e544b74d877ed5ca92763ef0ca0d7bfa08" + + "d57a0216b2a01a2b9ec74b8430051e0074862b7be25b6766ab520f2eb75d" + + "eeb979c28f03795f6f1e4b8410beab19a20febc91985b8a7c298534a6598" + + "f2c5b0dc5de9f5e55a97791507bc6373db26", + }, +} diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go index 6c6e8423..fd97ba1b 100644 --- a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go @@ -5,7 +5,7 @@ // Package ripemd160 implements the RIPEMD-160 hash algorithm. package ripemd160 // import "golang.org/x/crypto/ripemd160" -// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart +// RIPEMD-160 is designed by Hans Dobbertin, Antoon Bosselaers, and Bart // Preneel with specifications available at: // http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf. diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go index 5df1b259..a1fbffdd 100644 --- a/vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go @@ -50,15 +50,23 @@ func TestVectors(t *testing.T) { } } -func TestMillionA(t *testing.T) { +func millionA() string { md := New() for i := 0; i < 100000; i++ { io.WriteString(md, "aaaaaaaaaa") } - out := "52783243c1697bdbe16d37f97f68f08325dc1528" - s := fmt.Sprintf("%x", md.Sum(nil)) - if s != out { + return fmt.Sprintf("%x", md.Sum(nil)) +} + +func TestMillionA(t *testing.T) { + const out = "52783243c1697bdbe16d37f97f68f08325dc1528" + if s := millionA(); s != out { t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out) } - md.Reset() +} + +func BenchmarkMillionA(b *testing.B) { + for i := 0; i < b.N; i++ { + millionA() + } } diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go index 7bc8e6c4..e0edc02f 100644 --- a/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go +++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go @@ -8,6 +8,10 @@ package ripemd160 +import ( + "math/bits" +) + // work buffer indices and roll amounts for one line var _n = [80]uint{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -59,16 +63,16 @@ func _Block(md *digest, p []byte) int { i := 0 for i < 16 { alpha = a + (b ^ c ^ d) + x[_n[i]] - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6 - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ @@ -77,16 +81,16 @@ func _Block(md *digest, p []byte) int { // round 2 for i < 32 { alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999 - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124 - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ @@ -95,16 +99,16 @@ func _Block(md *digest, p []byte) int { // round 3 for i < 48 { alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1 - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3 - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ @@ -113,16 +117,16 @@ func _Block(md *digest, p []byte) int { // round 4 for i < 64 { alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9 - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ @@ -131,16 +135,16 @@ func _Block(md *digest, p []byte) int { // round 5 for i < 80 { alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e - s := _r[i] - alpha = (alpha<>(32-s)) + e - beta = c<<10 | c>>22 + s := int(_r[i]) + alpha = bits.RotateLeft32(alpha, s) + e + beta = bits.RotateLeft32(c, 10) a, b, c, d, e = e, alpha, b, beta, d // parallel line alpha = aa + (bb ^ cc ^ dd) + x[n_[i]] - s = r_[i] - alpha = (alpha<>(32-s)) + ee - beta = cc<<10 | cc>>22 + s = int(r_[i]) + alpha = bits.RotateLeft32(alpha, s) + ee + beta = bits.RotateLeft32(cc, 10) aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd i++ diff --git a/vendor/golang.org/x/crypto/salsa20/salsa20.go b/vendor/golang.org/x/crypto/salsa20/salsa20.go index 0ee62485..6f9bb106 100644 --- a/vendor/golang.org/x/crypto/salsa20/salsa20.go +++ b/vendor/golang.org/x/crypto/salsa20/salsa20.go @@ -24,6 +24,7 @@ package salsa20 // import "golang.org/x/crypto/salsa20" // TODO(agl): implement XORKeyStream12 and XORKeyStream8 - the reduced round variants of Salsa20. import ( + "golang.org/x/crypto/internal/subtle" "golang.org/x/crypto/salsa20/salsa" ) @@ -32,7 +33,10 @@ import ( // be either 8 or 24 bytes long. func XORKeyStream(out, in []byte, nonce []byte, key *[32]byte) { if len(out) < len(in) { - in = in[:len(out)] + panic("salsa20: output smaller than input") + } + if subtle.InexactOverlap(out[:len(in)], in) { + panic("salsa20: invalid buffer overlap") } var subNonce [16]byte diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go index ff28aaef..3362afd1 100644 --- a/vendor/golang.org/x/crypto/scrypt/scrypt.go +++ b/vendor/golang.org/x/crypto/scrypt/scrypt.go @@ -29,7 +29,7 @@ func blockXOR(dst, src []uint32, n int) { } // salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in, -// and puts the result into both both tmp and out. +// and puts the result into both tmp and out. func salsaXOR(tmp *[16]uint32, in, out []uint32) { w0 := tmp[0] ^ in[0] w1 := tmp[1] ^ in[1] @@ -218,7 +218,7 @@ func smix(b []byte, r, N int, v, xy []uint32) { // For example, you can get a derived key for e.g. AES-256 (which needs a // 32-byte key) by doing: // -// dk, err := scrypt.Key([]byte("some password"), salt, 16384, 8, 1, 32) +// dk, err := scrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32) // // The recommended parameters for interactive logins as of 2017 are N=32768, r=8 // and p=1. The parameters N, r, and p should be increased as memory latency and diff --git a/vendor/golang.org/x/crypto/sha3/doc.go b/vendor/golang.org/x/crypto/sha3/doc.go index a0ee3ae7..c2fef30a 100644 --- a/vendor/golang.org/x/crypto/sha3/doc.go +++ b/vendor/golang.org/x/crypto/sha3/doc.go @@ -43,7 +43,7 @@ // is then "full" and the permutation is applied to "empty" it. This process is // repeated until all the input has been "absorbed". The input is then padded. // The digest is "squeezed" from the sponge in the same way, except that output -// output is copied out instead of input being XORed in. +// is copied out instead of input being XORed in. // // A sponge is parameterized by its generic security strength, which is equal // to half its capacity; capacity + rate is equal to the permutation's width. diff --git a/vendor/golang.org/x/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go index 2b51cf4e..0d8043fd 100644 --- a/vendor/golang.org/x/crypto/sha3/hashes.go +++ b/vendor/golang.org/x/crypto/sha3/hashes.go @@ -15,22 +15,54 @@ import ( // New224 creates a new SHA3-224 hash. // Its generic security strength is 224 bits against preimage attacks, // and 112 bits against collision attacks. -func New224() hash.Hash { return &state{rate: 144, outputLen: 28, dsbyte: 0x06} } +func New224() hash.Hash { + if h := new224Asm(); h != nil { + return h + } + return &state{rate: 144, outputLen: 28, dsbyte: 0x06} +} // New256 creates a new SHA3-256 hash. // Its generic security strength is 256 bits against preimage attacks, // and 128 bits against collision attacks. -func New256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x06} } +func New256() hash.Hash { + if h := new256Asm(); h != nil { + return h + } + return &state{rate: 136, outputLen: 32, dsbyte: 0x06} +} // New384 creates a new SHA3-384 hash. // Its generic security strength is 384 bits against preimage attacks, // and 192 bits against collision attacks. -func New384() hash.Hash { return &state{rate: 104, outputLen: 48, dsbyte: 0x06} } +func New384() hash.Hash { + if h := new384Asm(); h != nil { + return h + } + return &state{rate: 104, outputLen: 48, dsbyte: 0x06} +} // New512 creates a new SHA3-512 hash. // Its generic security strength is 512 bits against preimage attacks, // and 256 bits against collision attacks. -func New512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x06} } +func New512() hash.Hash { + if h := new512Asm(); h != nil { + return h + } + return &state{rate: 72, outputLen: 64, dsbyte: 0x06} +} + +// NewLegacyKeccak256 creates a new Keccak-256 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New256 instead. +func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } + +// NewLegacyKeccak512 creates a new Keccak-512 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New512 instead. +func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} } // Sum224 returns the SHA3-224 digest of the data. func Sum224(data []byte) (digest [28]byte) { diff --git a/vendor/golang.org/x/crypto/sha3/hashes_generic.go b/vendor/golang.org/x/crypto/sha3/hashes_generic.go new file mode 100644 index 00000000..c4ff3f6e --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/hashes_generic.go @@ -0,0 +1,27 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build gccgo appengine !s390x + +package sha3 + +import ( + "hash" +) + +// new224Asm returns an assembly implementation of SHA3-224 if available, +// otherwise it returns nil. +func new224Asm() hash.Hash { return nil } + +// new256Asm returns an assembly implementation of SHA3-256 if available, +// otherwise it returns nil. +func new256Asm() hash.Hash { return nil } + +// new384Asm returns an assembly implementation of SHA3-384 if available, +// otherwise it returns nil. +func new384Asm() hash.Hash { return nil } + +// new512Asm returns an assembly implementation of SHA3-512 if available, +// otherwise it returns nil. +func new512Asm() hash.Hash { return nil } diff --git a/vendor/golang.org/x/crypto/sha3/sha3_s390x.go b/vendor/golang.org/x/crypto/sha3/sha3_s390x.go new file mode 100644 index 00000000..f1fb79cc --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/sha3_s390x.go @@ -0,0 +1,289 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build !gccgo,!appengine + +package sha3 + +// This file contains code for using the 'compute intermediate +// message digest' (KIMD) and 'compute last message digest' (KLMD) +// instructions to compute SHA-3 and SHAKE hashes on IBM Z. + +import ( + "hash" +) + +// codes represent 7-bit KIMD/KLMD function codes as defined in +// the Principles of Operation. +type code uint64 + +const ( + // function codes for KIMD/KLMD + sha3_224 code = 32 + sha3_256 = 33 + sha3_384 = 34 + sha3_512 = 35 + shake_128 = 36 + shake_256 = 37 + nopad = 0x100 +) + +// hasMSA6 reports whether the machine supports the SHA-3 and SHAKE function +// codes, as defined in message-security-assist extension 6. +func hasMSA6() bool + +// hasAsm caches the result of hasMSA6 (which might be expensive to call). +var hasAsm = hasMSA6() + +// kimd is a wrapper for the 'compute intermediate message digest' instruction. +// src must be a multiple of the rate for the given function code. +//go:noescape +func kimd(function code, chain *[200]byte, src []byte) + +// klmd is a wrapper for the 'compute last message digest' instruction. +// src padding is handled by the instruction. +//go:noescape +func klmd(function code, chain *[200]byte, dst, src []byte) + +type asmState struct { + a [200]byte // 1600 bit state + buf []byte // care must be taken to ensure cap(buf) is a multiple of rate + rate int // equivalent to block size + storage [3072]byte // underlying storage for buf + outputLen int // output length if fixed, 0 if not + function code // KIMD/KLMD function code + state spongeDirection // whether the sponge is absorbing or squeezing +} + +func newAsmState(function code) *asmState { + var s asmState + s.function = function + switch function { + case sha3_224: + s.rate = 144 + s.outputLen = 28 + case sha3_256: + s.rate = 136 + s.outputLen = 32 + case sha3_384: + s.rate = 104 + s.outputLen = 48 + case sha3_512: + s.rate = 72 + s.outputLen = 64 + case shake_128: + s.rate = 168 + case shake_256: + s.rate = 136 + default: + panic("sha3: unrecognized function code") + } + + // limit s.buf size to a multiple of s.rate + s.resetBuf() + return &s +} + +func (s *asmState) clone() *asmState { + c := *s + c.buf = c.storage[:len(s.buf):cap(s.buf)] + return &c +} + +// copyIntoBuf copies b into buf. It will panic if there is not enough space to +// store all of b. +func (s *asmState) copyIntoBuf(b []byte) { + bufLen := len(s.buf) + s.buf = s.buf[:len(s.buf)+len(b)] + copy(s.buf[bufLen:], b) +} + +// resetBuf points buf at storage, sets the length to 0 and sets cap to be a +// multiple of the rate. +func (s *asmState) resetBuf() { + max := (cap(s.storage) / s.rate) * s.rate + s.buf = s.storage[:0:max] +} + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (s *asmState) Write(b []byte) (int, error) { + if s.state != spongeAbsorbing { + panic("sha3: write to sponge after read") + } + length := len(b) + for len(b) > 0 { + if len(s.buf) == 0 && len(b) >= cap(s.buf) { + // Hash the data directly and push any remaining bytes + // into the buffer. + remainder := len(s.buf) % s.rate + kimd(s.function, &s.a, b[:len(b)-remainder]) + if remainder != 0 { + s.copyIntoBuf(b[len(b)-remainder:]) + } + return length, nil + } + + if len(s.buf) == cap(s.buf) { + // flush the buffer + kimd(s.function, &s.a, s.buf) + s.buf = s.buf[:0] + } + + // copy as much as we can into the buffer + n := len(b) + if len(b) > cap(s.buf)-len(s.buf) { + n = cap(s.buf) - len(s.buf) + } + s.copyIntoBuf(b[:n]) + b = b[n:] + } + return length, nil +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (s *asmState) Read(out []byte) (n int, err error) { + n = len(out) + + // need to pad if we were absorbing + if s.state == spongeAbsorbing { + s.state = spongeSqueezing + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function, &s.a, out, s.buf) // len(out) may be 0 + s.buf = s.buf[:0] + return + } + + // write hash into buffer + max := cap(s.buf) + if max > len(out) { + max = (len(out)/s.rate)*s.rate + s.rate + } + klmd(s.function, &s.a, s.buf[:max], s.buf) + s.buf = s.buf[:max] + } + + for len(out) > 0 { + // flush the buffer + if len(s.buf) != 0 { + c := copy(out, s.buf) + out = out[c:] + s.buf = s.buf[c:] + continue + } + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function|nopad, &s.a, out, nil) + return + } + + // write hash into buffer + s.resetBuf() + if cap(s.buf) > len(out) { + s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate] + } + klmd(s.function|nopad, &s.a, s.buf, nil) + } + return +} + +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (s *asmState) Sum(b []byte) []byte { + if s.outputLen == 0 { + panic("sha3: cannot call Sum on SHAKE functions") + } + + // Copy the state to preserve the original. + a := s.a + + // Hash the buffer. Note that we don't clear it because we + // aren't updating the state. + klmd(s.function, &a, nil, s.buf) + return append(b, a[:s.outputLen]...) +} + +// Reset resets the Hash to its initial state. +func (s *asmState) Reset() { + for i := range s.a { + s.a[i] = 0 + } + s.resetBuf() + s.state = spongeAbsorbing +} + +// Size returns the number of bytes Sum will return. +func (s *asmState) Size() int { + return s.outputLen +} + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (s *asmState) BlockSize() int { + return s.rate +} + +// Clone returns a copy of the ShakeHash in its current state. +func (s *asmState) Clone() ShakeHash { + return s.clone() +} + +// new224Asm returns an assembly implementation of SHA3-224 if available, +// otherwise it returns nil. +func new224Asm() hash.Hash { + if hasAsm { + return newAsmState(sha3_224) + } + return nil +} + +// new256Asm returns an assembly implementation of SHA3-256 if available, +// otherwise it returns nil. +func new256Asm() hash.Hash { + if hasAsm { + return newAsmState(sha3_256) + } + return nil +} + +// new384Asm returns an assembly implementation of SHA3-384 if available, +// otherwise it returns nil. +func new384Asm() hash.Hash { + if hasAsm { + return newAsmState(sha3_384) + } + return nil +} + +// new512Asm returns an assembly implementation of SHA3-512 if available, +// otherwise it returns nil. +func new512Asm() hash.Hash { + if hasAsm { + return newAsmState(sha3_512) + } + return nil +} + +// newShake128Asm returns an assembly implementation of SHAKE-128 if available, +// otherwise it returns nil. +func newShake128Asm() ShakeHash { + if hasAsm { + return newAsmState(shake_128) + } + return nil +} + +// newShake256Asm returns an assembly implementation of SHAKE-256 if available, +// otherwise it returns nil. +func newShake256Asm() ShakeHash { + if hasAsm { + return newAsmState(shake_256) + } + return nil +} diff --git a/vendor/golang.org/x/crypto/sha3/sha3_s390x.s b/vendor/golang.org/x/crypto/sha3/sha3_s390x.s new file mode 100644 index 00000000..20978fc7 --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/sha3_s390x.s @@ -0,0 +1,49 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build !gccgo,!appengine + +#include "textflag.h" + +TEXT ·hasMSA6(SB), NOSPLIT, $16-1 + MOVD $0, R0 // KIMD-Query function code + MOVD $tmp-16(SP), R1 // parameter block + XC $16, (R1), (R1) // clear the parameter block + WORD $0xB93E0002 // KIMD --, -- + WORD $0x91FC1004 // TM 4(R1), 0xFC (test bits [32-37]) + BVS yes + +no: + MOVB $0, ret+0(FP) + RET + +yes: + MOVB $1, ret+0(FP) + RET + +// func kimd(function code, params *[200]byte, src []byte) +TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 + MOVD function+0(FP), R0 + MOVD params+8(FP), R1 + LMG src+16(FP), R2, R3 // R2=base, R3=len + +continue: + WORD $0xB93E0002 // KIMD --, R2 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET + +// func klmd(function code, params *[200]byte, dst, src []byte) +TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 + // TODO: SHAKE support + MOVD function+0(FP), R0 + MOVD params+8(FP), R1 + LMG dst+16(FP), R2, R3 // R2=base, R3=len + LMG src+40(FP), R4, R5 // R4=base, R5=len + +continue: + WORD $0xB93F0024 // KLMD R2, R4 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET diff --git a/vendor/golang.org/x/crypto/sha3/sha3_test.go b/vendor/golang.org/x/crypto/sha3/sha3_test.go index 2c8719b4..26d1549b 100644 --- a/vendor/golang.org/x/crypto/sha3/sha3_test.go +++ b/vendor/golang.org/x/crypto/sha3/sha3_test.go @@ -36,15 +36,17 @@ func newHashShake256() hash.Hash { } // testDigests contains functions returning hash.Hash instances -// with output-length equal to the KAT length for both SHA-3 and -// SHAKE instances. +// with output-length equal to the KAT length for SHA-3, Keccak +// and SHAKE instances. var testDigests = map[string]func() hash.Hash{ - "SHA3-224": New224, - "SHA3-256": New256, - "SHA3-384": New384, - "SHA3-512": New512, - "SHAKE128": newHashShake128, - "SHAKE256": newHashShake256, + "SHA3-224": New224, + "SHA3-256": New256, + "SHA3-384": New384, + "SHA3-512": New512, + "Keccak-256": NewLegacyKeccak256, + "Keccak-512": NewLegacyKeccak512, + "SHAKE128": newHashShake128, + "SHAKE256": newHashShake256, } // testShakes contains functions that return ShakeHash instances for @@ -124,9 +126,39 @@ func TestKeccakKats(t *testing.T) { }) } +// TestKeccak does a basic test of the non-standardized Keccak hash functions. +func TestKeccak(t *testing.T) { + tests := []struct { + fn func() hash.Hash + data []byte + want string + }{ + { + NewLegacyKeccak256, + []byte("abc"), + "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45", + }, + { + NewLegacyKeccak512, + []byte("abc"), + "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96", + }, + } + + for _, u := range tests { + h := u.fn() + h.Write(u.data) + got := h.Sum(nil) + want := decodeHex(u.want) + if !bytes.Equal(got, want) { + t.Errorf("unexpected hash for size %d: got '%x' want '%s'", h.Size()*8, got, u.want) + } + } +} + // TestUnalignedWrite tests that writing data in an arbitrary pattern with // small input buffers. -func testUnalignedWrite(t *testing.T) { +func TestUnalignedWrite(t *testing.T) { testUnalignedAndGeneric(t, func(impl string) { buf := sequentialBytes(0x10000) for alg, df := range testDigests { diff --git a/vendor/golang.org/x/crypto/sha3/shake.go b/vendor/golang.org/x/crypto/sha3/shake.go index 841f9860..97c9b062 100644 --- a/vendor/golang.org/x/crypto/sha3/shake.go +++ b/vendor/golang.org/x/crypto/sha3/shake.go @@ -38,12 +38,22 @@ func (d *state) Clone() ShakeHash { // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. // Its generic security strength is 128 bits against all attacks if at // least 32 bytes of its output are used. -func NewShake128() ShakeHash { return &state{rate: 168, dsbyte: 0x1f} } +func NewShake128() ShakeHash { + if h := newShake128Asm(); h != nil { + return h + } + return &state{rate: 168, dsbyte: 0x1f} +} -// NewShake256 creates a new SHAKE128 variable-output-length ShakeHash. +// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. // Its generic security strength is 256 bits against all attacks if // at least 64 bytes of its output are used. -func NewShake256() ShakeHash { return &state{rate: 136, dsbyte: 0x1f} } +func NewShake256() ShakeHash { + if h := newShake256Asm(); h != nil { + return h + } + return &state{rate: 136, dsbyte: 0x1f} +} // ShakeSum128 writes an arbitrary-length digest of data into hash. func ShakeSum128(hash, data []byte) { diff --git a/vendor/golang.org/x/crypto/sha3/shake_generic.go b/vendor/golang.org/x/crypto/sha3/shake_generic.go new file mode 100644 index 00000000..73d0c90b --- /dev/null +++ b/vendor/golang.org/x/crypto/sha3/shake_generic.go @@ -0,0 +1,19 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//+build gccgo appengine !s390x + +package sha3 + +// newShake128Asm returns an assembly implementation of SHAKE-128 if available, +// otherwise it returns nil. +func newShake128Asm() ShakeHash { + return nil +} + +// newShake256Asm returns an assembly implementation of SHAKE-256 if available, +// otherwise it returns nil. +func newShake256Asm() ShakeHash { + return nil +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go index acb5ad80..51f74050 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/client.go +++ b/vendor/golang.org/x/crypto/ssh/agent/client.go @@ -8,7 +8,7 @@ // ssh-agent process using the sample server. // // References: -// [PROTOCOL.agent]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD +// [PROTOCOL.agent]: https://tools.ietf.org/html/draft-miller-ssh-agent-00 package agent // import "golang.org/x/crypto/ssh/agent" import ( @@ -25,10 +25,22 @@ import ( "math/big" "sync" + "crypto" "golang.org/x/crypto/ed25519" "golang.org/x/crypto/ssh" ) +// SignatureFlags represent additional flags that can be passed to the signature +// requests an defined in [PROTOCOL.agent] section 4.5.1. +type SignatureFlags uint32 + +// SignatureFlag values as defined in [PROTOCOL.agent] section 5.3. +const ( + SignatureFlagReserved SignatureFlags = 1 << iota + SignatureFlagRsaSha256 + SignatureFlagRsaSha512 +) + // Agent represents the capabilities of an ssh-agent. type Agent interface { // List returns the identities known to the agent. @@ -57,6 +69,26 @@ type Agent interface { Signers() ([]ssh.Signer, error) } +type ExtendedAgent interface { + Agent + + // SignWithFlags signs like Sign, but allows for additional flags to be sent/received + SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) + + // Extension processes a custom extension request. Standard-compliant agents are not + // required to support any extensions, but this method allows agents to implement + // vendor-specific methods or add experimental features. See [PROTOCOL.agent] section 4.7. + // If agent extensions are unsupported entirely this method MUST return an + // ErrExtensionUnsupported error. Similarly, if just the specific extensionType in + // the request is unsupported by the agent then ErrExtensionUnsupported MUST be + // returned. + // + // In the case of success, since [PROTOCOL.agent] section 4.7 specifies that the contents + // of the response are unspecified (including the type of the message), the complete + // response will be returned as a []byte slice, including the "type" byte of the message. + Extension(extensionType string, contents []byte) ([]byte, error) +} + // ConstraintExtension describes an optional constraint defined by users. type ConstraintExtension struct { // ExtensionName consist of a UTF-8 string suffixed by the @@ -179,6 +211,23 @@ type constrainExtensionAgentMsg struct { Rest []byte `ssh:"rest"` } +// See [PROTOCOL.agent], section 4.7 +const agentExtension = 27 +const agentExtensionFailure = 28 + +// ErrExtensionUnsupported indicates that an extension defined in +// [PROTOCOL.agent] section 4.7 is unsupported by the agent. Specifically this +// error indicates that the agent returned a standard SSH_AGENT_FAILURE message +// as the result of a SSH_AGENTC_EXTENSION request. Note that the protocol +// specification (and therefore this error) does not distinguish between a +// specific extension being unsupported and extensions being unsupported entirely. +var ErrExtensionUnsupported = errors.New("agent: extension unsupported") + +type extensionAgentMsg struct { + ExtensionType string `sshtype:"27"` + Contents []byte +} + // Key represents a protocol 2 public key as defined in // [PROTOCOL.agent], section 2.5.2. type Key struct { @@ -260,7 +309,7 @@ type client struct { // NewClient returns an Agent that talks to an ssh-agent process over // the given connection. -func NewClient(rw io.ReadWriter) Agent { +func NewClient(rw io.ReadWriter) ExtendedAgent { return &client{conn: rw} } @@ -268,6 +317,21 @@ func NewClient(rw io.ReadWriter) Agent { // unmarshaled into reply and replyType is set to the first byte of // the reply, which contains the type of the message. func (c *client) call(req []byte) (reply interface{}, err error) { + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + reply, err = unmarshal(buf) + if err != nil { + return nil, clientErr(err) + } + return reply, nil +} + +// callRaw sends an RPC to the agent. On success, the raw +// bytes of the response are returned; no unmarshalling is +// performed on the response. +func (c *client) callRaw(req []byte) (reply []byte, err error) { c.mu.Lock() defer c.mu.Unlock() @@ -284,18 +348,14 @@ func (c *client) call(req []byte) (reply interface{}, err error) { } respSize := binary.BigEndian.Uint32(respSizeBuf[:]) if respSize > maxAgentResponseBytes { - return nil, clientErr(err) + return nil, clientErr(errors.New("response too large")) } buf := make([]byte, respSize) if _, err = io.ReadFull(c.conn, buf); err != nil { return nil, clientErr(err) } - reply, err = unmarshal(buf) - if err != nil { - return nil, clientErr(err) - } - return reply, err + return buf, nil } func (c *client) simpleCall(req []byte) error { @@ -369,9 +429,14 @@ func (c *client) List() ([]*Key, error) { // Sign has the agent sign the data using a protocol 2 key as defined // in [PROTOCOL.agent] section 2.6.2. func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return c.SignWithFlags(key, data, 0) +} + +func (c *client) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { req := ssh.Marshal(signRequestAgentMsg{ KeyBlob: key.Marshal(), Data: data, + Flags: uint32(flags), }) msg, err := c.call(req) @@ -681,3 +746,44 @@ func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, // The agent has its own entropy source, so the rand argument is ignored. return s.agent.Sign(s.pub, data) } + +func (s *agentKeyringSigner) SignWithOpts(rand io.Reader, data []byte, opts crypto.SignerOpts) (*ssh.Signature, error) { + var flags SignatureFlags + if opts != nil { + switch opts.HashFunc() { + case crypto.SHA256: + flags = SignatureFlagRsaSha256 + case crypto.SHA512: + flags = SignatureFlagRsaSha512 + } + } + return s.agent.SignWithFlags(s.pub, data, flags) +} + +// Calls an extension method. It is up to the agent implementation as to whether or not +// any particular extension is supported and may always return an error. Because the +// type of the response is up to the implementation, this returns the bytes of the +// response and does not attempt any type of unmarshalling. +func (c *client) Extension(extensionType string, contents []byte) ([]byte, error) { + req := ssh.Marshal(extensionAgentMsg{ + ExtensionType: extensionType, + Contents: contents, + }) + buf, err := c.callRaw(req) + if err != nil { + return nil, err + } + if len(buf) == 0 { + return nil, errors.New("agent: failure; empty response") + } + // [PROTOCOL.agent] section 4.7 indicates that an SSH_AGENT_FAILURE message + // represents an agent that does not support the extension + if buf[0] == agentFailure { + return nil, ErrExtensionUnsupported + } + if buf[0] == agentExtensionFailure { + return nil, errors.New("agent: generic extension failure") + } + + return buf, nil +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/client_test.go b/vendor/golang.org/x/crypto/ssh/agent/client_test.go index 266fd6d4..2f798f94 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/client_test.go +++ b/vendor/golang.org/x/crypto/ssh/agent/client_test.go @@ -20,7 +20,7 @@ import ( ) // startOpenSSHAgent executes ssh-agent, and returns an Agent interface to it. -func startOpenSSHAgent(t *testing.T) (client Agent, socket string, cleanup func()) { +func startOpenSSHAgent(t *testing.T) (client ExtendedAgent, socket string, cleanup func()) { if testing.Short() { // ssh-agent is not always available, and the key // types supported vary by platform. @@ -79,13 +79,12 @@ func startOpenSSHAgent(t *testing.T) (client Agent, socket string, cleanup func( } } -// startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client. -func startKeyringAgent(t *testing.T) (client Agent, cleanup func()) { +func startAgent(t *testing.T, agent Agent) (client ExtendedAgent, cleanup func()) { c1, c2, err := netPipe() if err != nil { t.Fatalf("netPipe: %v", err) } - go ServeAgent(NewKeyring(), c2) + go ServeAgent(agent, c2) return NewClient(c1), func() { c1.Close() @@ -93,6 +92,11 @@ func startKeyringAgent(t *testing.T) (client Agent, cleanup func()) { } } +// startKeyringAgent uses Keyring to simulate a ssh-agent Server and returns a client. +func startKeyringAgent(t *testing.T) (client ExtendedAgent, cleanup func()) { + return startAgent(t, NewKeyring()) +} + func testOpenSSHAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { agent, _, cleanup := startOpenSSHAgent(t) defer cleanup() @@ -107,7 +111,7 @@ func testKeyringAgent(t *testing.T, key interface{}, cert *ssh.Certificate, life testAgentInterface(t, agent, key, cert, lifetimeSecs) } -func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { +func testAgentInterface(t *testing.T, agent ExtendedAgent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) { signer, err := ssh.NewSignerFromKey(key) if err != nil { t.Fatalf("NewSignerFromKey(%T): %v", key, err) @@ -159,6 +163,25 @@ func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Ce t.Fatalf("Verify(%s): %v", pubKey.Type(), err) } + // For tests on RSA keys, try signing with SHA-256 and SHA-512 flags + if pubKey.Type() == "ssh-rsa" { + sshFlagTest := func(flag SignatureFlags, expectedSigFormat string) { + sig, err = agent.SignWithFlags(pubKey, data, flag) + if err != nil { + t.Fatalf("SignWithFlags(%s): %v", pubKey.Type(), err) + } + if sig.Format != expectedSigFormat { + t.Fatalf("Signature format didn't match expected value: %s != %s", sig.Format, expectedSigFormat) + } + if err := pubKey.Verify(data, sig); err != nil { + t.Fatalf("Verify(%s): %v", pubKey.Type(), err) + } + } + sshFlagTest(0, ssh.SigAlgoRSA) + sshFlagTest(SignatureFlagRsaSha256, ssh.SigAlgoRSASHA2256) + sshFlagTest(SignatureFlagRsaSha512, ssh.SigAlgoRSASHA2512) + } + // If the key has a lifetime, is it removed when it should be? if lifetimeSecs > 0 { time.Sleep(time.Second*time.Duration(lifetimeSecs) + 100*time.Millisecond) @@ -218,6 +241,35 @@ func netPipe() (net.Conn, net.Conn, error) { return c1, c2, nil } +func TestServerResponseTooLarge(t *testing.T) { + a, b, err := netPipe() + if err != nil { + t.Fatalf("netPipe: %v", err) + } + + defer a.Close() + defer b.Close() + + var response identitiesAnswerAgentMsg + response.NumKeys = 1 + response.Keys = make([]byte, maxAgentResponseBytes+1) + + agent := NewClient(a) + go func() { + n, _ := b.Write(ssh.Marshal(response)) + if n < 4 { + t.Fatalf("At least 4 bytes (the response size) should have been successfully written: %d < 4", n) + } + }() + _, err = agent.List() + if err == nil { + t.Fatal("Did not get error result") + } + if err.Error() != "agent: client error: response too large" { + t.Fatal("Did not get expected error result") + } +} + func TestAuth(t *testing.T) { agent, _, cleanup := startOpenSSHAgent(t) defer cleanup() @@ -377,3 +429,38 @@ func testAgentLifetime(t *testing.T, agent Agent) { t.Errorf("Want 0 keys, got %v", len(keys)) } } + +type keyringExtended struct { + *keyring +} + +func (r *keyringExtended) Extension(extensionType string, contents []byte) ([]byte, error) { + if extensionType != "my-extension@example.com" { + return []byte{agentExtensionFailure}, nil + } + return append([]byte{agentSuccess}, contents...), nil +} + +func TestAgentExtensions(t *testing.T) { + agent, _, cleanup := startOpenSSHAgent(t) + defer cleanup() + result, err := agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02}) + if err == nil { + t.Fatal("should have gotten agent extension failure") + } + + agent, cleanup = startAgent(t, &keyringExtended{}) + defer cleanup() + result, err = agent.Extension("my-extension@example.com", []byte{0x00, 0x01, 0x02}) + if err != nil { + t.Fatalf("agent extension failure: %v", err) + } + if len(result) != 4 || !bytes.Equal(result, []byte{agentSuccess, 0x00, 0x01, 0x02}) { + t.Fatalf("agent extension result invalid: %v", result) + } + + result, err = agent.Extension("bad-extension@example.com", []byte{0x00, 0x01, 0x02}) + if err == nil { + t.Fatal("should have gotten agent extension failure") + } +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go index a6ba06ab..c9d97943 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/keyring.go +++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go @@ -102,7 +102,7 @@ func (r *keyring) Unlock(passphrase []byte) error { if !r.locked { return errors.New("agent: not locked") } - if len(passphrase) != len(r.passphrase) || 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) { + if 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) { return fmt.Errorf("agent: incorrect passphrase") } @@ -182,6 +182,10 @@ func (r *keyring) Add(key AddedKey) error { // Sign returns a signature for the data. func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { + return r.SignWithFlags(key, data, 0) +} + +func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags SignatureFlags) (*ssh.Signature, error) { r.mu.Lock() defer r.mu.Unlock() if r.locked { @@ -192,7 +196,24 @@ func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { wanted := key.Marshal() for _, k := range r.keys { if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) { - return k.signer.Sign(rand.Reader, data) + if flags == 0 { + return k.signer.Sign(rand.Reader, data) + } else { + if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok { + return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer) + } else { + var algorithm string + switch flags { + case SignatureFlagRsaSha256: + algorithm = ssh.SigAlgoRSASHA2256 + case SignatureFlagRsaSha512: + algorithm = ssh.SigAlgoRSASHA2512 + default: + return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags) + } + return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) + } + } } } return nil, errors.New("not found") @@ -213,3 +234,8 @@ func (r *keyring) Signers() ([]ssh.Signer, error) { } return s, nil } + +// The keyring does not support any extensions +func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) { + return nil, ErrExtensionUnsupported +} diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go index 2e4692cb..a1949762 100644 --- a/vendor/golang.org/x/crypto/ssh/agent/server.go +++ b/vendor/golang.org/x/crypto/ssh/agent/server.go @@ -128,7 +128,14 @@ func (s *server) processRequest(data []byte) (interface{}, error) { Blob: req.KeyBlob, } - sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. + var sig *ssh.Signature + var err error + if extendedAgent, ok := s.agent.(ExtendedAgent); ok { + sig, err = extendedAgent.SignWithFlags(k, req.Data, SignatureFlags(req.Flags)) + } else { + sig, err = s.agent.Sign(k, req.Data) + } + if err != nil { return nil, err } @@ -150,6 +157,43 @@ func (s *server) processRequest(data []byte) (interface{}, error) { case agentAddIDConstrained, agentAddIdentity: return nil, s.insertIdentity(data) + + case agentExtension: + // Return a stub object where the whole contents of the response gets marshaled. + var responseStub struct { + Rest []byte `ssh:"rest"` + } + + if extendedAgent, ok := s.agent.(ExtendedAgent); !ok { + // If this agent doesn't implement extensions, [PROTOCOL.agent] section 4.7 + // requires that we return a standard SSH_AGENT_FAILURE message. + responseStub.Rest = []byte{agentFailure} + } else { + var req extensionAgentMsg + if err := ssh.Unmarshal(data, &req); err != nil { + return nil, err + } + res, err := extendedAgent.Extension(req.ExtensionType, req.Contents) + if err != nil { + // If agent extensions are unsupported, return a standard SSH_AGENT_FAILURE + // message as required by [PROTOCOL.agent] section 4.7. + if err == ErrExtensionUnsupported { + responseStub.Rest = []byte{agentFailure} + } else { + // As the result of any other error processing an extension request, + // [PROTOCOL.agent] section 4.7 requires that we return a + // SSH_AGENT_EXTENSION_FAILURE code. + responseStub.Rest = []byte{agentExtensionFailure} + } + } else { + if len(res) == 0 { + return nil, nil + } + responseStub.Rest = res + } + } + + return responseStub, nil } return nil, fmt.Errorf("unknown opcode %d", data[0]) diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go index 42106f3f..00ed9923 100644 --- a/vendor/golang.org/x/crypto/ssh/certs.go +++ b/vendor/golang.org/x/crypto/ssh/certs.go @@ -222,6 +222,11 @@ type openSSHCertSigner struct { signer Signer } +type algorithmOpenSSHCertSigner struct { + *openSSHCertSigner + algorithmSigner AlgorithmSigner +} + // NewCertSigner returns a Signer that signs with the given Certificate, whose // private key is held by signer. It returns an error if the public key in cert // doesn't match the key used by signer. @@ -230,7 +235,12 @@ func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { return nil, errors.New("ssh: signer and cert have different public key") } - return &openSSHCertSigner{cert, signer}, nil + if algorithmSigner, ok := signer.(AlgorithmSigner); ok { + return &algorithmOpenSSHCertSigner{ + &openSSHCertSigner{cert, signer}, algorithmSigner}, nil + } else { + return &openSSHCertSigner{cert, signer}, nil + } } func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { @@ -241,6 +251,10 @@ func (s *openSSHCertSigner) PublicKey() PublicKey { return s.pub } +func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) +} + const sourceAddressCriticalOption = "source-address" // CertChecker does the work of verifying a certificate. Its methods diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go index 30a49fdf..67b01261 100644 --- a/vendor/golang.org/x/crypto/ssh/cipher.go +++ b/vendor/golang.org/x/crypto/ssh/cipher.go @@ -16,6 +16,7 @@ import ( "hash" "io" "io/ioutil" + "math/bits" "golang.org/x/crypto/internal/chacha20" "golang.org/x/crypto/poly1305" @@ -641,8 +642,8 @@ const chacha20Poly1305ID = "chacha20-poly1305@openssh.com" // the methods here also implement padding, which RFC4253 Section 6 // also requires of stream ciphers. type chacha20Poly1305Cipher struct { - lengthKey [32]byte - contentKey [32]byte + lengthKey [8]uint32 + contentKey [8]uint32 buf []byte } @@ -655,20 +656,21 @@ func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionA buf: make([]byte, 256), } - copy(c.contentKey[:], key[:32]) - copy(c.lengthKey[:], key[32:]) + for i := range c.contentKey { + c.contentKey[i] = binary.LittleEndian.Uint32(key[i*4 : (i+1)*4]) + } + for i := range c.lengthKey { + c.lengthKey[i] = binary.LittleEndian.Uint32(key[(i+8)*4 : (i+9)*4]) + } return c, nil } -// The Poly1305 key is obtained by encrypting 32 0-bytes. -var chacha20PolyKeyInput [32]byte - func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { - var counter [16]byte - binary.BigEndian.PutUint64(counter[8:], uint64(seqNum)) - + nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} + s := chacha20.New(c.contentKey, nonce) var polyKey [32]byte - chacha20.XORKeyStream(polyKey[:], chacha20PolyKeyInput[:], &counter, &c.contentKey) + s.XORKeyStream(polyKey[:], polyKey[:]) + s.Advance() // skip next 32 bytes encryptedLength := c.buf[:4] if _, err := io.ReadFull(r, encryptedLength); err != nil { @@ -676,7 +678,7 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, } var lenBytes [4]byte - chacha20.XORKeyStream(lenBytes[:], encryptedLength, &counter, &c.lengthKey) + chacha20.New(c.lengthKey, nonce).XORKeyStream(lenBytes[:], encryptedLength) length := binary.BigEndian.Uint32(lenBytes[:]) if length > maxPacket { @@ -702,10 +704,8 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, return nil, errors.New("ssh: MAC failure") } - counter[0] = 1 - plain := c.buf[4:contentEnd] - chacha20.XORKeyStream(plain, plain, &counter, &c.contentKey) + s.XORKeyStream(plain, plain) padding := plain[0] if padding < 4 { @@ -724,11 +724,11 @@ func (c *chacha20Poly1305Cipher) readPacket(seqNum uint32, r io.Reader) ([]byte, } func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { - var counter [16]byte - binary.BigEndian.PutUint64(counter[8:], uint64(seqNum)) - + nonce := [3]uint32{0, 0, bits.ReverseBytes32(seqNum)} + s := chacha20.New(c.contentKey, nonce) var polyKey [32]byte - chacha20.XORKeyStream(polyKey[:], chacha20PolyKeyInput[:], &counter, &c.contentKey) + s.XORKeyStream(polyKey[:], polyKey[:]) + s.Advance() // skip next 32 bytes // There is no blocksize, so fall back to multiple of 8 byte // padding, as described in RFC 4253, Sec 6. @@ -748,7 +748,7 @@ func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io } binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding)) - chacha20.XORKeyStream(c.buf, c.buf[:4], &counter, &c.lengthKey) + chacha20.New(c.lengthKey, nonce).XORKeyStream(c.buf, c.buf[:4]) c.buf[4] = byte(padding) copy(c.buf[5:], payload) packetEnd := 5 + len(payload) + padding @@ -756,8 +756,7 @@ func (c *chacha20Poly1305Cipher) writePacket(seqNum uint32, w io.Writer, rand io return err } - counter[0] = 1 - chacha20.XORKeyStream(c.buf[4:], c.buf[4:packetEnd], &counter, &c.contentKey) + s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd]) var mac [poly1305.TagSize]byte poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey) diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go index 6fd19945..7b00bff1 100644 --- a/vendor/golang.org/x/crypto/ssh/client.go +++ b/vendor/golang.org/x/crypto/ssh/client.go @@ -19,6 +19,8 @@ import ( type Client struct { Conn + handleForwardsOnce sync.Once // guards calling (*Client).handleForwards + forwards forwardList // forwarded tcpip connections from the remote side mu sync.Mutex channelHandlers map[string]chan NewChannel @@ -60,8 +62,6 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { conn.Wait() conn.forwards.closeAll() }() - go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip")) - go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com")) return conn } @@ -185,7 +185,7 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) { // keys. A HostKeyCallback must return nil if the host key is OK, or // an error to reject it. It receives the hostname as passed to Dial // or NewClientConn. The remote address is the RemoteAddr of the -// net.Conn underlying the the SSH connection. +// net.Conn underlying the SSH connection. type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error // BannerCallback is the function type used for treat the banner sent by diff --git a/vendor/golang.org/x/crypto/ssh/client_auth_test.go b/vendor/golang.org/x/crypto/ssh/client_auth_test.go index e457ca53..026d137e 100644 --- a/vendor/golang.org/x/crypto/ssh/client_auth_test.go +++ b/vendor/golang.org/x/crypto/ssh/client_auth_test.go @@ -9,6 +9,7 @@ import ( "crypto/rand" "errors" "fmt" + "io" "os" "strings" "testing" @@ -28,8 +29,14 @@ func (cr keyboardInteractive) Challenge(user string, instruction string, questio var clientPassword = "tiger" // tryAuth runs a handshake with a given config against an SSH server -// with config serverConfig +// with config serverConfig. Returns both client and server side errors. func tryAuth(t *testing.T, config *ClientConfig) error { + err, _ := tryAuthBothSides(t, config) + return err +} + +// tryAuthBothSides runs the handshake and returns the resulting errors from both sides of the connection. +func tryAuthBothSides(t *testing.T, config *ClientConfig) (clientError error, serverAuthErrors []error) { c1, c2, err := netPipe() if err != nil { t.Fatalf("netPipe: %v", err) @@ -79,9 +86,13 @@ func tryAuth(t *testing.T, config *ClientConfig) error { } serverConfig.AddHostKey(testSigners["rsa"]) + serverConfig.AuthLogCallback = func(conn ConnMetadata, method string, err error) { + serverAuthErrors = append(serverAuthErrors, err) + } + go newServer(c1, serverConfig) _, _, _, err = NewClientConn(c2, "", config) - return err + return err, serverAuthErrors } func TestClientAuthPublicKey(t *testing.T) { @@ -213,6 +224,45 @@ func TestAuthMethodRSAandDSA(t *testing.T) { } } +type invalidAlgSigner struct { + Signer +} + +func (s *invalidAlgSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + sig, err := s.Signer.Sign(rand, data) + if sig != nil { + sig.Format = "invalid" + } + return sig, err +} + +func TestMethodInvalidAlgorithm(t *testing.T) { + config := &ClientConfig{ + User: "testuser", + Auth: []AuthMethod{ + PublicKeys(&invalidAlgSigner{testSigners["rsa"]}), + }, + HostKeyCallback: InsecureIgnoreHostKey(), + } + + err, serverErrors := tryAuthBothSides(t, config) + if err == nil { + t.Fatalf("login succeeded") + } + + found := false + want := "algorithm \"invalid\"" + + var errStrings []string + for _, err := range serverErrors { + found = found || (err != nil && strings.Contains(err.Error(), want)) + errStrings = append(errStrings, err.Error()) + } + if !found { + t.Errorf("server got error %q, want substring %q", errStrings, want) + } +} + func TestClientHMAC(t *testing.T) { for _, mac := range supportedMACs { config := &ClientConfig{ @@ -614,8 +664,8 @@ func TestClientAuthErrorList(t *testing.T) { for i, e := range authErrs.Errors { switch i { case 0: - if e != NoAuthError { - t.Fatalf("errors: got error %v, want NoAuthError", e) + if e != ErrNoAuth { + t.Fatalf("errors: got error %v, want ErrNoAuth", e) } case 1: if e != publicKeyErr { diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go index dadf41ab..96980479 100644 --- a/vendor/golang.org/x/crypto/ssh/keys.go +++ b/vendor/golang.org/x/crypto/ssh/keys.go @@ -38,6 +38,16 @@ const ( KeyAlgoED25519 = "ssh-ed25519" ) +// These constants represent non-default signature algorithms that are supported +// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See +// [PROTOCOL.agent] section 4.5.1 and +// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10 +const ( + SigAlgoRSA = "ssh-rsa" + SigAlgoRSASHA2256 = "rsa-sha2-256" + SigAlgoRSASHA2512 = "rsa-sha2-512" +) + // parsePubKey parses a public key of the given algorithm. // Use ParsePublicKey for keys with prepended algorithm. func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { @@ -276,7 +286,8 @@ type PublicKey interface { Type() string // Marshal returns the serialized key data in SSH wire format, - // with the name prefix. + // with the name prefix. To unmarshal the returned data, use + // the ParsePublicKey function. Marshal() []byte // Verify that sig is a signature on the given data using this @@ -300,6 +311,19 @@ type Signer interface { Sign(rand io.Reader, data []byte) (*Signature, error) } +// A AlgorithmSigner is a Signer that also supports specifying a specific +// algorithm to use for signing. +type AlgorithmSigner interface { + Signer + + // SignWithAlgorithm is like Signer.Sign, but allows specification of a + // non-default signing algorithm. See the SigAlgo* constants in this + // package for signature algorithms supported by this package. Callers may + // pass an empty string for the algorithm in which case the AlgorithmSigner + // will use its default algorithm. + SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) +} + type rsaPublicKey rsa.PublicKey func (r *rsaPublicKey) Type() string { @@ -348,13 +372,21 @@ func (r *rsaPublicKey) Marshal() []byte { } func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { - if sig.Format != r.Type() { + var hash crypto.Hash + switch sig.Format { + case SigAlgoRSA: + hash = crypto.SHA1 + case SigAlgoRSASHA2256: + hash = crypto.SHA256 + case SigAlgoRSASHA2512: + hash = crypto.SHA512 + default: return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) } - h := crypto.SHA1.New() + h := hash.New() h.Write(data) digest := h.Sum(nil) - return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob) + return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) } func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { @@ -458,6 +490,14 @@ func (k *dsaPrivateKey) PublicKey() PublicKey { } func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { + return k.SignWithAlgorithm(rand, data, "") +} + +func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { + if algorithm != "" && algorithm != k.PublicKey().Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + h := crypto.SHA1.New() h.Write(data) digest := h.Sum(nil) @@ -690,16 +730,42 @@ func (s *wrappedSigner) PublicKey() PublicKey { } func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { + return s.SignWithAlgorithm(rand, data, "") +} + +func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { var hashFunc crypto.Hash - switch key := s.pubKey.(type) { - case *rsaPublicKey, *dsaPublicKey: - hashFunc = crypto.SHA1 - case *ecdsaPublicKey: - hashFunc = ecHash(key.Curve) - case ed25519PublicKey: - default: - return nil, fmt.Errorf("ssh: unsupported key type %T", key) + if _, ok := s.pubKey.(*rsaPublicKey); ok { + // RSA keys support a few hash functions determined by the requested signature algorithm + switch algorithm { + case "", SigAlgoRSA: + algorithm = SigAlgoRSA + hashFunc = crypto.SHA1 + case SigAlgoRSASHA2256: + hashFunc = crypto.SHA256 + case SigAlgoRSASHA2512: + hashFunc = crypto.SHA512 + default: + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + } else { + // The only supported algorithm for all other key types is the same as the type of the key + if algorithm == "" { + algorithm = s.pubKey.Type() + } else if algorithm != s.pubKey.Type() { + return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) + } + + switch key := s.pubKey.(type) { + case *dsaPublicKey: + hashFunc = crypto.SHA1 + case *ecdsaPublicKey: + hashFunc = ecHash(key.Curve) + case ed25519PublicKey: + default: + return nil, fmt.Errorf("ssh: unsupported key type %T", key) + } } var digest []byte @@ -744,7 +810,7 @@ func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { } return &Signature{ - Format: s.pubKey.Type(), + Format: algorithm, Blob: signature, }, nil } @@ -802,7 +868,7 @@ func encryptedBlock(block *pem.Block) bool { } // ParseRawPrivateKey returns a private key from a PEM encoded private key. It -// supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys. +// supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { block, _ := pem.Decode(pemBytes) if block == nil { @@ -816,6 +882,9 @@ func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { switch block.Type { case "RSA PRIVATE KEY": return x509.ParsePKCS1PrivateKey(block.Bytes) + // RFC5208 - https://tools.ietf.org/html/rfc5208 + case "PRIVATE KEY": + return x509.ParsePKCS8PrivateKey(block.Bytes) case "EC PRIVATE KEY": return x509.ParseECPrivateKey(block.Bytes) case "DSA PRIVATE KEY": @@ -899,8 +968,8 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { // Implemented based on the documentation at // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key func parseOpenSSHPrivateKey(key []byte) (crypto.PrivateKey, error) { - magic := append([]byte("openssh-key-v1"), 0) - if !bytes.Equal(magic, key[0:len(magic)]) { + const magic = "openssh-key-v1\x00" + if len(key) < len(magic) || string(key[:len(magic)]) != magic { return nil, errors.New("ssh: invalid openssh private key format") } remaining := key[len(magic):] diff --git a/vendor/golang.org/x/crypto/ssh/keys_test.go b/vendor/golang.org/x/crypto/ssh/keys_test.go index 9a90abc0..3847b3bf 100644 --- a/vendor/golang.org/x/crypto/ssh/keys_test.go +++ b/vendor/golang.org/x/crypto/ssh/keys_test.go @@ -13,7 +13,9 @@ import ( "crypto/rsa" "crypto/x509" "encoding/base64" + "encoding/pem" "fmt" + "io" "reflect" "strings" "testing" @@ -107,6 +109,49 @@ func TestKeySignVerify(t *testing.T) { } } +func TestKeySignWithAlgorithmVerify(t *testing.T) { + for _, priv := range testSigners { + if algorithmSigner, ok := priv.(AlgorithmSigner); !ok { + t.Errorf("Signers constructed by ssh package should always implement the AlgorithmSigner interface: %T", priv) + } else { + pub := priv.PublicKey() + data := []byte("sign me") + + signWithAlgTestCase := func(algorithm string, expectedAlg string) { + sig, err := algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm) + if err != nil { + t.Fatalf("Sign(%T): %v", priv, err) + } + if sig.Format != expectedAlg { + t.Errorf("signature format did not match requested signature algorithm: %s != %s", sig.Format, expectedAlg) + } + + if err := pub.Verify(data, sig); err != nil { + t.Errorf("publicKey.Verify(%T): %v", priv, err) + } + sig.Blob[5]++ + if err := pub.Verify(data, sig); err == nil { + t.Errorf("publicKey.Verify on broken sig did not fail") + } + } + + // Using the empty string as the algorithm name should result in the same signature format as the algorithm-free Sign method. + defaultSig, err := priv.Sign(rand.Reader, data) + if err != nil { + t.Fatalf("Sign(%T): %v", priv, err) + } + signWithAlgTestCase("", defaultSig.Format) + + // RSA keys are the only ones which currently support more than one signing algorithm + if pub.Type() == KeyAlgoRSA { + for _, algorithm := range []string{SigAlgoRSA, SigAlgoRSASHA2256, SigAlgoRSASHA2512} { + signWithAlgTestCase(algorithm, algorithm) + } + } + } + } +} + func TestParseRSAPrivateKey(t *testing.T) { key := testPrivateKeys["rsa"] @@ -498,3 +543,32 @@ func TestFingerprintSHA256(t *testing.T) { t.Errorf("got fingerprint %q want %q", fingerprint, want) } } + +func TestInvalidKeys(t *testing.T) { + keyTypes := []string{ + "RSA PRIVATE KEY", + "PRIVATE KEY", + "EC PRIVATE KEY", + "DSA PRIVATE KEY", + "OPENSSH PRIVATE KEY", + } + + for _, keyType := range keyTypes { + for _, dataLen := range []int{0, 1, 2, 5, 10, 20} { + data := make([]byte, dataLen) + if _, err := io.ReadFull(rand.Reader, data); err != nil { + t.Fatal(err) + } + + var buf bytes.Buffer + pem.Encode(&buf, &pem.Block{ + Type: keyType, + Bytes: data, + }) + + // This test is just to ensure that the function + // doesn't panic so the return value is ignored. + ParseRawPrivateKey(buf.Bytes()) + } + } +} diff --git a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go index 46dad140..bc3db737 100644 --- a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go +++ b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts.go @@ -2,8 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package knownhosts implements a parser for the OpenSSH -// known_hosts host key database. +// Package knownhosts implements a parser for the OpenSSH known_hosts +// host key database, and provides utility functions for writing +// OpenSSH compliant known_hosts files. package knownhosts import ( @@ -38,7 +39,7 @@ func (a *addr) String() string { } type matcher interface { - match([]addr) bool + match(addr) bool } type hostPattern struct { @@ -57,19 +58,16 @@ func (p *hostPattern) String() string { type hostPatterns []hostPattern -func (ps hostPatterns) match(addrs []addr) bool { +func (ps hostPatterns) match(a addr) bool { matched := false for _, p := range ps { - for _, a := range addrs { - m := p.match(a) - if !m { - continue - } - if p.negate { - return false - } - matched = true + if !p.match(a) { + continue } + if p.negate { + return false + } + matched = true } return matched } @@ -122,8 +120,8 @@ func serialize(k ssh.PublicKey) string { return k.Type() + " " + base64.StdEncoding.EncodeToString(k.Marshal()) } -func (l *keyDBLine) match(addrs []addr) bool { - return l.matcher.match(addrs) +func (l *keyDBLine) match(a addr) bool { + return l.matcher.match(a) } type hostKeyDB struct { @@ -153,7 +151,7 @@ func (db *hostKeyDB) IsHostAuthority(remote ssh.PublicKey, address string) bool a := addr{host: h, port: p} for _, l := range db.lines { - if l.cert && keyEq(l.knownKey.Key, remote) && l.match([]addr{a}) { + if l.cert && keyEq(l.knownKey.Key, remote) && l.match(a) { return true } } @@ -338,26 +336,24 @@ func (db *hostKeyDB) check(address string, remote net.Addr, remoteKey ssh.Public return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", remote, err) } - addrs := []addr{ - {host, port}, - } - + hostToCheck := addr{host, port} if address != "" { + // Give preference to the hostname if available. host, port, err := net.SplitHostPort(address) if err != nil { return fmt.Errorf("knownhosts: SplitHostPort(%s): %v", address, err) } - addrs = append(addrs, addr{host, port}) + hostToCheck = addr{host, port} } - return db.checkAddrs(addrs, remoteKey) + return db.checkAddr(hostToCheck, remoteKey) } // checkAddrs checks if we can find the given public key for any of // the given addresses. If we only find an entry for the IP address, // or only the hostname, then this still succeeds. -func (db *hostKeyDB) checkAddrs(addrs []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 // is just a key for the IP address, but not for the // hostname? @@ -365,7 +361,7 @@ func (db *hostKeyDB) checkAddrs(addrs []addr, remoteKey ssh.PublicKey) error { // Algorithm => key. knownKeys := map[string]KnownKey{} for _, l := range db.lines { - if l.match(addrs) { + if l.match(a) { typ := l.knownKey.Key.Type() if _, ok := knownKeys[typ]; !ok { knownKeys[typ] = l.knownKey @@ -414,7 +410,10 @@ func (db *hostKeyDB) Read(r io.Reader, filename string) error { // New creates a host key callback from the given OpenSSH host key // files. The returned callback is for use in -// ssh.ClientConfig.HostKeyCallback. +// ssh.ClientConfig.HostKeyCallback. By preference, the key check +// operates on the hostname if available, i.e. if a server changes its +// IP address, the host key check will still succeed, even though a +// record of the new IP address is not available. func New(files ...string) (ssh.HostKeyCallback, error) { db := newHostKeyDB() for _, fn := range files { @@ -536,11 +535,6 @@ func newHashedHost(encoded string) (*hashedHost, error) { return &hashedHost{salt: salt, hash: hash}, nil } -func (h *hashedHost) match(addrs []addr) bool { - for _, a := range addrs { - if bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash) { - return true - } - } - return false +func (h *hashedHost) match(a addr) bool { + return bytes.Equal(hashHost(Normalize(a.String()), h.salt), h.hash) } diff --git a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts_test.go b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts_test.go index be7cc0e8..464dd592 100644 --- a/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts_test.go +++ b/vendor/golang.org/x/crypto/ssh/knownhosts/knownhosts_test.go @@ -166,7 +166,7 @@ func TestBasic(t *testing.T) { str := fmt.Sprintf("#comment\n\nserver.org,%s %s\notherhost %s", testAddr, edKeyStr, ecKeyStr) db := testDB(t, str) if err := db.check("server.org:22", testAddr, edKey); err != nil { - t.Errorf("got error %q, want none", err) + t.Errorf("got error %v, want none", err) } want := KnownKey{ @@ -185,6 +185,33 @@ func TestBasic(t *testing.T) { } } +func TestHostNamePrecedence(t *testing.T) { + var evilAddr = &net.TCPAddr{ + IP: net.IP{66, 66, 66, 66}, + Port: 22, + } + + str := fmt.Sprintf("server.org,%s %s\nevil.org,%s %s", testAddr, edKeyStr, evilAddr, ecKeyStr) + db := testDB(t, str) + + if err := db.check("server.org:22", evilAddr, ecKey); err == nil { + t.Errorf("check succeeded") + } else if _, ok := err.(*KeyError); !ok { + t.Errorf("got %T, want *KeyError", err) + } +} + +func TestDBOrderingPrecedenceKeyType(t *testing.T) { + str := fmt.Sprintf("server.org,%s %s\nserver.org,%s %s", testAddr, edKeyStr, testAddr, alternateEdKeyStr) + db := testDB(t, str) + + if err := db.check("server.org:22", testAddr, alternateEdKey); err == nil { + t.Errorf("check succeeded") + } else if _, ok := err.(*KeyError); !ok { + t.Errorf("got %T, want *KeyError", err) + } +} + func TestNegate(t *testing.T) { str := fmt.Sprintf("%s,!server.org %s", testAddr, edKeyStr) db := testDB(t, str) diff --git a/vendor/golang.org/x/crypto/ssh/mux_test.go b/vendor/golang.org/x/crypto/ssh/mux_test.go index 25d2181d..94596ec2 100644 --- a/vendor/golang.org/x/crypto/ssh/mux_test.go +++ b/vendor/golang.org/x/crypto/ssh/mux_test.go @@ -20,7 +20,7 @@ func muxPair() (*mux, *mux) { return s, c } -// Returns both ends of a channel, and the mux for the the 2nd +// Returns both ends of a channel, and the mux for the 2nd // channel. func channelPair(t *testing.T) (*channel, *channel, *mux) { c, s := muxPair() @@ -108,10 +108,6 @@ func TestMuxReadWrite(t *testing.T) { if err != nil { t.Fatalf("Write: %v", err) } - err = s.Close() - if err != nil { - t.Fatalf("Close: %v", err) - } }() var buf [1024]byte diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index 6262f341..e86e8966 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -166,6 +166,9 @@ type ServerConn struct { // unsuccessful, it closes the connection and returns an error. The // Request and NewChannel channels must be serviced, or the connection // will hang. +// +// The returned error may be of type *ServerAuthError for +// authentication errors. func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { fullConf := *config fullConf.SetDefaults() @@ -292,12 +295,13 @@ func checkSourceAddress(addr net.Addr, sourceAddrs string) error { return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) } -// ServerAuthError implements the error interface. It appends any authentication -// errors that may occur, and is returned if all of the authentication methods -// provided by the user failed to authenticate. +// ServerAuthError represents server authentication errors and is +// sometimes returned by NewServerConn. It appends any authentication +// errors that may occur, and is returned if all of the authentication +// methods provided by the user failed to authenticate. type ServerAuthError struct { // Errors contains authentication errors returned by the authentication - // callback methods. The first entry typically is NoAuthError. + // callback methods. The first entry is typically ErrNoAuth. Errors []error } @@ -309,11 +313,12 @@ func (l ServerAuthError) Error() string { return "[" + strings.Join(errs, ", ") + "]" } -// NoAuthError is the unique error that is returned if no +// ErrNoAuth is the error value returned if no // authentication method has been passed yet. This happens as a normal // part of the authentication loop, since the client first tries // 'none' authentication to discover available methods. -var NoAuthError = errors.New("ssh: no auth passed yet") +// It is returned in ServerAuthError.Errors from NewServerConn. +var ErrNoAuth = errors.New("ssh: no auth passed yet") func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { sessionID := s.transport.getSessionID() @@ -369,7 +374,7 @@ userAuthLoop: } perms = nil - authErr := NoAuthError + authErr := ErrNoAuth switch userAuthReq.Method { case "none": @@ -399,7 +404,7 @@ userAuthLoop: perms, authErr = config.PasswordCallback(s, password) case "keyboard-interactive": if config.KeyboardInteractiveCallback == nil { - authErr = errors.New("ssh: keyboard-interactive auth not configubred") + authErr = errors.New("ssh: keyboard-interactive auth not configured") break } @@ -479,6 +484,7 @@ userAuthLoop: // sig.Format. This is usually the same, but // for certs, the names differ. if !isAcceptableAlgo(sig.Format) { + authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format) break } signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) diff --git a/vendor/golang.org/x/crypto/ssh/sshpiper.go b/vendor/golang.org/x/crypto/ssh/sshpiper.go index 19dee484..3eeaf0b8 100644 --- a/vendor/golang.org/x/crypto/ssh/sshpiper.go +++ b/vendor/golang.org/x/crypto/ssh/sshpiper.go @@ -55,6 +55,22 @@ type AuthPipe struct { UpstreamHostKeyCallback HostKeyCallback } +// The context returned by AdditionalChallenge and will pass to FindUpstream for building +// upstream AuthPipe +type AdditionalChallengeContext interface { + + // Chanllenger name + ChanllengerName() string + + // Meta info filled by chanllenger + // can be nil if no meta data + Meta() interface{} + + // Username used during the chanllenge + // Can be different from ConnMeta.User() and could be a useful hint in FindUpstream + ChanllengedUsername() string +} + // PiperConfig holds SSHPiper specific configuration data. type PiperConfig struct { Config @@ -63,16 +79,18 @@ type PiperConfig struct { // AdditionalChallenge, if non-nil, is called before calling FindUpstream. // This allows you do a KeyboardInteractiveChallenge before connecting to upstream. - // It must return true if downstream passed the challenge, otherwise, + // It must return non error if downstream passed the challenge, otherwise, // the piped connection will be closed. - AdditionalChallenge func(conn ConnMetadata, client KeyboardInteractiveChallenge) (bool, error) + // + // AdditionalChallengeContext can be nil if challenger has no more information to provide. + AdditionalChallenge func(conn ConnMetadata, client KeyboardInteractiveChallenge) (AdditionalChallengeContext, error) // FindUpstream, must not be nil, is called when SSHPiper decided to establish a // ssh connection to upstream server. a connection, net.Conn, to upstream // and upstream username should be returned. // SSHPiper will use the username from downstream if empty username is returned. // If any error occurs, the piped connection will be closed. - FindUpstream func(conn ConnMetadata) (net.Conn, *AuthPipe, error) + FindUpstream func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) // ServerVersion is the version identification string to announce in // the public handshake. @@ -189,6 +207,8 @@ func NewSSHPiperConn(conn net.Conn, piper *PiperConfig) (pipe *PiperConn, err er d.user = userAuthReq.User + var challengeCtx AdditionalChallengeContext + // need additional challenge if piper.AdditionalChallenge != nil { @@ -213,18 +233,14 @@ func NewSSHPiperConn(conn net.Conn, piper *PiperConfig) (pipe *PiperConn, err er } prompter := &sshClientKeyboardInteractive{d.connection} - ok, err := piper.AdditionalChallenge(d, prompter.Challenge) + challengeCtx, err = piper.AdditionalChallenge(d, prompter.Challenge) if err != nil { return nil, err } - - if !ok { - return nil, fmt.Errorf("additional challenge failed") - } } - upconn, pipeauth, err := piper.FindUpstream(d) + upconn, pipeauth, err := piper.FindUpstream(d, challengeCtx) if err != nil { return nil, err } diff --git a/vendor/golang.org/x/crypto/ssh/sshpiper_test.go b/vendor/golang.org/x/crypto/ssh/sshpiper_test.go index 6ac9bce1..9875760c 100644 --- a/vendor/golang.org/x/crypto/ssh/sshpiper_test.go +++ b/vendor/golang.org/x/crypto/ssh/sshpiper_test.go @@ -22,7 +22,7 @@ func ExampleNewSSHPiperConn() { piper := &PiperConfig{ // return conn dial to serverAddr - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { c, err := net.Dial("tcp", serverAddr) if err != nil { return nil, nil, err @@ -107,7 +107,7 @@ func TestPiperFindUpstreamCallback(t *testing.T) { var called bool c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { if username != conn.User() { t.Errorf("different username") } @@ -158,7 +158,7 @@ func TestPiperFindUpstreamWithUserCallback(t *testing.T) { var called bool c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { s, err := dialUpstream(simpleEchoHandler, &ServerConfig{ PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { @@ -213,7 +213,7 @@ func TestPiperMapPublicKey(t *testing.T) { } c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { s, err := dialUpstream(simpleEchoHandler, &ServerConfig{ PublicKeyCallback: certChecker.Authenticate, }, t) @@ -265,7 +265,7 @@ func TestPiperMapPublicKeyToPassword(t *testing.T) { var called bool c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { s, err := dialUpstream(simpleEchoHandler, &ServerConfig{ PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { t.Errorf("PasswordCallback should not be called") @@ -316,7 +316,7 @@ func TestPiperPasswordToMapPublicKey(t *testing.T) { var called bool c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { s, err := dialUpstream(simpleEchoHandler, &ServerConfig{ PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { called = true @@ -373,7 +373,7 @@ func TestPiperServerWithBanner(t *testing.T) { var called bool c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { if username != conn.User() { t.Errorf("different username") } @@ -442,7 +442,7 @@ func TestPiperUsernameNotChangedWithinSession(t *testing.T) { } c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { s, err := dialUpstream(simpleEchoHandler, &ServerConfig{ PasswordCallback: func(conn ConnMetadata, password []byte) (*Permissions, error) { if conn.User() != mappedname { @@ -501,26 +501,38 @@ func TestPiperUsernameNotChangedWithinSession(t *testing.T) { } } +type fakeChallengerContext string + +func (fakeChallengerContext) ChanllengerName() string { return "" } +func (fakeChallengerContext) Meta() interface{} { return nil } +func (c fakeChallengerContext) ChanllengedUsername() string { return string(c) } + func TestPiperAdditionalChallenge(t *testing.T) { + c, err := dialPiper(&PiperConfig{ - AdditionalChallenge: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (bool, error) { + AdditionalChallenge: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (AdditionalChallengeContext, error) { ans, err := challenge("user", "instruction", []string{"question1", "question2"}, []bool{true, true}) if err != nil { - return false, err + return nil, err } ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2" if ok { challenge("user", "motd", nil, nil) - return true, nil + return fakeChallengerContext("chal"), nil } - return false, fmt.Errorf("keyboard-interactive failed") + return nil, fmt.Errorf("keyboard-interactive failed") }, - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { + + if challengeCtx.ChanllengedUsername() != "chal" { + t.Fatalf("challengeCtx.ChanllengedUsername changed") + } + s, err := dialUpstream(simpleEchoHandler, &ServerConfig{NoClientAuth: true}, t) return s, &AuthPipe{ UpstreamHostKeyCallback: InsecureIgnoreHostKey(), @@ -597,7 +609,7 @@ func TestPiperConnMeta(t *testing.T) { wait := make(chan int) c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { s, err := dialUpstream(simpleEchoHandler, &ServerConfig{NoClientAuth: true}, t) return s, &AuthPipe{ User: "up", @@ -635,7 +647,7 @@ func TestPiperConnMsgHook(t *testing.T) { wait := make(chan int) c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { s, err := dialUpstream(simpleEchoHandler, &ServerConfig{NoClientAuth: true}, t) return s, &AuthPipe{ UpstreamHostKeyCallback: InsecureIgnoreHostKey(), @@ -730,7 +742,7 @@ func TestPiperConnMsgHook(t *testing.T) { func TestPiperPipeData(t *testing.T) { c, err := dialPiper(&PiperConfig{ - FindUpstream: func(conn ConnMetadata) (net.Conn, *AuthPipe, error) { + FindUpstream: func(conn ConnMetadata, challengeCtx AdditionalChallengeContext) (net.Conn, *AuthPipe, error) { s, err := dialUpstream(simpleEchoHandler, &ServerConfig{NoClientAuth: true}, t) return s, &AuthPipe{ UpstreamHostKeyCallback: InsecureIgnoreHostKey(), diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go index a2dccc64..b171b330 100644 --- a/vendor/golang.org/x/crypto/ssh/streamlocal.go +++ b/vendor/golang.org/x/crypto/ssh/streamlocal.go @@ -32,6 +32,7 @@ type streamLocalChannelForwardMsg struct { // ListenUnix is similar to ListenTCP but uses a Unix domain socket. func (c *Client) ListenUnix(socketPath string) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) m := streamLocalChannelForwardMsg{ socketPath, } diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go index acf17175..80d35f5e 100644 --- a/vendor/golang.org/x/crypto/ssh/tcpip.go +++ b/vendor/golang.org/x/crypto/ssh/tcpip.go @@ -90,10 +90,19 @@ type channelForwardMsg struct { rport uint32 } +// handleForwards starts goroutines handling forwarded connections. +// It's called on first use by (*Client).ListenTCP to not launch +// goroutines until needed. +func (c *Client) handleForwards() { + go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-tcpip")) + go c.forwards.handleChannels(c.HandleChannelOpen("forwarded-streamlocal@openssh.com")) +} + // ListenTCP requests the remote peer open a listening socket // on laddr. Incoming connections will be available by calling // Accept on the returned net.Listener. func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { + c.handleForwardsOnce.Do(c.handleForwards) if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { return c.autoPortListenWorkaround(laddr) } diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go index 901c72ab..5e5d33b1 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go @@ -2,12 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd windows plan9 solaris + package terminal import ( "bytes" "io" "os" + "runtime" "testing" ) @@ -324,6 +327,11 @@ func TestMakeRawState(t *testing.T) { if err != nil { t.Fatalf("failed to get terminal state from GetState: %s", err) } + + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + t.Skip("MakeRaw not allowed on iOS; skipping test") + } + defer Restore(fd, st) raw, err := MakeRaw(fd) if err != nil { diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go index 02dad484..39110408 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd +// +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd // Package terminal provides support functions for dealing with terminals, as // commonly found on UNIX systems. @@ -25,7 +25,7 @@ type State struct { termios unix.Termios } -// IsTerminal returns true if the given file descriptor is a terminal. +// IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { _, err := unix.IoctlGetTermios(fd, ioctlReadTermios) return err == nil @@ -108,9 +108,7 @@ func ReadPassword(fd int) ([]byte, error) { return nil, err } - defer func() { - unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) - }() + defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) return readPasswordLine(passwordReader(fd)) } diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go b/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go new file mode 100644 index 00000000..dfcd6278 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_aix.go @@ -0,0 +1,12 @@ +// 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 aix + +package terminal + +import "golang.org/x/sys/unix" + +const ioctlReadTermios = unix.TCGETS +const ioctlWriteTermios = unix.TCSETS diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go index 799f049f..9317ac7e 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go @@ -21,7 +21,7 @@ import ( type State struct{} -// IsTerminal returns true if the given file descriptor is a terminal. +// IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { return false } diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go index a2e1b57d..3d5f06a9 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go @@ -14,10 +14,10 @@ import ( // State contains the state of a terminal. type State struct { - state *unix.Termios + termios unix.Termios } -// IsTerminal returns true if the given file descriptor is a terminal. +// IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { _, err := unix.IoctlGetTermio(fd, unix.TCGETA) return err == nil @@ -75,47 +75,43 @@ func ReadPassword(fd int) ([]byte, error) { // restored. // see http://cr.illumos.org/~webrev/andy_js/1060/ func MakeRaw(fd int) (*State, error) { - oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS) + termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) if err != nil { return nil, err } - oldTermios := *oldTermiosPtr - newTermios := oldTermios - newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON - newTermios.Oflag &^= syscall.OPOST - newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN - newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB - newTermios.Cflag |= syscall.CS8 - newTermios.Cc[unix.VMIN] = 1 - newTermios.Cc[unix.VTIME] = 0 + oldState := State{termios: *termios} - if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil { + termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON + termios.Oflag &^= unix.OPOST + termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN + termios.Cflag &^= unix.CSIZE | unix.PARENB + termios.Cflag |= unix.CS8 + termios.Cc[unix.VMIN] = 1 + termios.Cc[unix.VTIME] = 0 + + if err := unix.IoctlSetTermios(fd, unix.TCSETS, termios); err != nil { return nil, err } - return &State{ - state: oldTermiosPtr, - }, nil + return &oldState, nil } // Restore restores the terminal connected to the given file descriptor to a // previous state. func Restore(fd int, oldState *State) error { - return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state) + return unix.IoctlSetTermios(fd, unix.TCSETS, &oldState.termios) } // GetState returns the current state of a terminal which may be useful to // restore the terminal after a signal. func GetState(fd int) (*State, error) { - oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS) + termios, err := unix.IoctlGetTermios(fd, unix.TCGETS) if err != nil { return nil, err } - return &State{ - state: oldTermiosPtr, - }, nil + return &State{termios: *termios}, nil } // GetSize returns the dimensions of the given terminal. diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go index 4933ac36..6cb8a950 100644 --- a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go +++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go @@ -26,7 +26,7 @@ type State struct { mode uint32 } -// IsTerminal returns true if the given file descriptor is a terminal. +// IsTerminal returns whether the given file descriptor is a terminal. func IsTerminal(fd int) bool { var st uint32 err := windows.GetConsoleMode(windows.Handle(fd), &st) @@ -89,9 +89,7 @@ func ReadPassword(fd int) ([]byte, error) { return nil, err } - defer func() { - windows.SetConsoleMode(windows.Handle(fd), old) - }() + defer windows.SetConsoleMode(windows.Handle(fd), old) var h windows.Handle p, _ := windows.GetCurrentProcess() diff --git a/vendor/golang.org/x/crypto/ssh/test/test_unix_test.go b/vendor/golang.org/x/crypto/ssh/test/test_unix_test.go index 39607868..2fbe880a 100644 --- a/vendor/golang.org/x/crypto/ssh/test/test_unix_test.go +++ b/vendor/golang.org/x/crypto/ssh/test/test_unix_test.go @@ -302,6 +302,13 @@ func newServerForConfig(t *testing.T, config string, configVars map[string]strin if testing.Short() { t.Skip("skipping test due to -short") } + u, err := user.Current() + if err != nil { + t.Fatalf("user.Current: %v", err) + } + if u.Name == "root" { + t.Skip("skipping test because current user is root") + } dir, err := ioutil.TempDir("", "sshtest") if err != nil { t.Fatal(err) diff --git a/vendor/golang.org/x/crypto/ssh/testdata/keys.go b/vendor/golang.org/x/crypto/ssh/testdata/keys.go index 521b6be9..bfae85fe 100644 --- a/vendor/golang.org/x/crypto/ssh/testdata/keys.go +++ b/vendor/golang.org/x/crypto/ssh/testdata/keys.go @@ -60,6 +60,35 @@ NDvRS0rjwt6lJGv7zPZoqDc65VfrK2aNyHx2PgFyzwrEOtuF57bu7pnvEIxpLTeM z26i6XVMeYXAWZMTloMCQBbpGgEERQpeUknLBqUHhg/wXF6+lFA+vEGnkY+Dwab2 KCXFGd+SQ5GdUcEMe9isUH6DYj/6/yCDoFrXXmpQb+M= -----END RSA PRIVATE KEY----- +`), + "pkcs8": []byte(`-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCitzS2KiRQTccf +VApb0mbPpo1lt29JjeLBYAehXHWfQ+w8sXpd8e04n/020spx1R94yg+v0NjXyh2R +NFXNBYdhNei33VJxUeKNlExaecvW2yxfuZqka+ZxT1aI8zrAsjh3Rwc6wayAJS4R +wZuzlDv4jZitWqwD+mb/22Zwq/WSs4YX5dUHDklfdWSVnoBfue8K/00n8f5yMTdJ +vFF0qAJwf9spPEHla0lYcozJk64CO5lRkqfLor4UnsXXOiA7aRIoaUSKa+rlhiqt +1EMGYiBjblPt4SwMelGGU2UfywPb4d85gpQ/s8SBARbpPxNVs2IbHDMwj70P3uZc +74M3c4VJAgMBAAECggEAFIzY3mziGzZHgMBncoNXMsCRORh6uKpvygZr0EhSHqRA +cMXlc3n7gNxL6aGjqc7F48Z5RrY0vMQtCcq3T2Z0W6WoV5hfMiqqV0E0h3S8ds1F +hG13h26NMyBXCILXl8Cqev4Afr45IBISCHIQTRTaoiCX+MTr1rDIU2YNQQumvzkz +fMw2XiFTFTgxAtJUAgKoTqLtm7/T+az7TKw+Hesgbx7yaJoMh9DWGBh4Y61DnIDA +fcxJboAfxxnFiXvdBVmzo72pCsRXrWOsjW6WxQmCKuXHvyB1FZTmMaEFNCGSJDa6 +U+OCzA3m65loAZAE7ffFHhYgssz/h9TBaOjKO0BX1QKBgQDZiCBvu+bFh9pEodcS +VxaI+ATlsYcmGdLtnZw5pxuEdr60iNWhpEcV6lGkbdiv5aL43QaGFDLagqeHI77b ++ITFbPPdCiYNaqlk6wyiXv4pdN7V683EDmGWSQlPeC9IhUilt2c+fChK2EB/XlkO +q8c3Vk1MsC6JOxDXNgJxylNpswKBgQC/fYBTb9iD+uM2n3SzJlct/ZlPaONKnNDR +pbTOdxBFHsu2VkfY858tfnEPkmSRX0yKmjHni6e8/qIzfzLwWBY4NmxhNZE5v+qJ +qZF26ULFdrZB4oWXAOliy/1S473OpQnp2MZp2asd0LPcg/BNaMuQrz44hxHb76R7 +qWD0ebIfEwKBgQCRCIiP1pjbVGN7ZOgPS080DSC+wClahtcyI+ZYLglTvRQTLDQ7 +LFtUykCav748MIADKuJBnM/3DiuCF5wV71EejDDfS/fo9BdyuKBY1brhixFTUX+E +Ww5Hc/SoLnpgALVZ/7jvWTpIBHykLxRziqYtR/YLzl+IkX/97P2ePoZ0rwKBgHNC +/7M5Z4JJyepfIMeVFHTCaT27TNTkf20x6Rs937U7TDN8y9JzEiU4LqXI4HAAhPoI +xnExRs4kF04YCnlRDE7Zs3Lv43J3ap1iTATfcymYwyv1RaQXEGQ/lUQHgYCZJtZz +fTrJoo5XyWu6nzJ5Gc8FLNaptr5ECSXGVm3Rsr2xAoGBAJWqEEQS/ejhO05QcPqh +y4cUdLr0269ILVsvic4Ot6zgfPIntXAK6IsHGKcg57kYm6W9k1CmmlA4ENGryJnR +vxyyqA9eyTFc1CQNuc2frKFA9It49JzjXahKc0aDHEHmTR787Tmk1LbuT0/gm9kA +L4INU6g+WqF0fatJxd+IJPrp +-----END PRIVATE KEY----- `), "ed25519": []byte(`-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW @@ -126,7 +155,7 @@ var SSHCertificates = map[string][]byte{ // Generated by the following commands: // // 1. Assumes "rsa" key above in file named "rsa", write out the public key to "rsa.pub": - // ssh-keygen -y -f rsa > rsa.pu + // ssh-keygen -y -f rsa > rsa.pub // // 2. Assumes "ca" key above in file named "ca", sign a cert for "rsa.pub": // ssh-keygen -s ca -h -n host.example.com -V +500w -I host.example.com-key rsa.pub diff --git a/vendor/golang.org/x/crypto/xtea/block.go b/vendor/golang.org/x/crypto/xtea/block.go index bf5d2459..fcb4e4d0 100644 --- a/vendor/golang.org/x/crypto/xtea/block.go +++ b/vendor/golang.org/x/crypto/xtea/block.go @@ -50,7 +50,7 @@ func encryptBlock(c *Cipher, dst, src []byte) { uint32ToBlock(v0, v1, dst) } -// decryptBlock decrypt a single 8 byte block using XTEA. +// decryptBlock decrypts a single 8 byte block using XTEA. func decryptBlock(c *Cipher, dst, src []byte) { v0, v1 := blockToUint32(src) diff --git a/vendor/golang.org/x/crypto/xtea/cipher.go b/vendor/golang.org/x/crypto/xtea/cipher.go index 66ea0df1..1661cbea 100644 --- a/vendor/golang.org/x/crypto/xtea/cipher.go +++ b/vendor/golang.org/x/crypto/xtea/cipher.go @@ -14,8 +14,8 @@ import "strconv" const BlockSize = 8 // A Cipher is an instance of an XTEA cipher using a particular key. -// table contains a series of precalculated values that are used each round. type Cipher struct { + // table contains a series of precalculated values that are used each round. table [64]uint32 } @@ -54,7 +54,7 @@ func (c *Cipher) BlockSize() int { return BlockSize } // instead, use an encryption mode like CBC (see crypto/cipher/cbc.go). func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) } -// Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst. +// Decrypt decrypts the 8 byte buffer src using the key and stores the result in dst. func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c, dst, src) } // initCipher initializes the cipher context by creating a look up table diff --git a/vendor/golang.org/x/crypto/xts/xts.go b/vendor/golang.org/x/crypto/xts/xts.go index 92cbce99..9654e1fc 100644 --- a/vendor/golang.org/x/crypto/xts/xts.go +++ b/vendor/golang.org/x/crypto/xts/xts.go @@ -25,6 +25,8 @@ import ( "crypto/cipher" "encoding/binary" "errors" + + "golang.org/x/crypto/internal/subtle" ) // Cipher contains an expanded key structure. It doesn't contain mutable state @@ -64,6 +66,9 @@ func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) { if len(plaintext)%blockSize != 0 { panic("xts: plaintext is not a multiple of the block size") } + if subtle.InexactOverlap(ciphertext[:len(plaintext)], plaintext) { + panic("xts: invalid buffer overlap") + } var tweak [blockSize]byte binary.LittleEndian.PutUint64(tweak[:8], sectorNum) @@ -95,6 +100,9 @@ func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) { if len(ciphertext)%blockSize != 0 { panic("xts: ciphertext is not a multiple of the block size") } + if subtle.InexactOverlap(plaintext[:len(ciphertext)], ciphertext) { + panic("xts: invalid buffer overlap") + } var tweak [blockSize]byte binary.LittleEndian.PutUint64(tweak[:8], sectorNum)