Compare commits

..
Author SHA1 Message Date
Filippo Valsorda 8b5121be2f [release-branch.go1.13] cryptobyte: fix panic due to malformed ASN.1 inputs on 32-bit archs
When int is 32 bits wide (on 32-bit architectures like 386 and arm), an
overflow could occur, causing a panic, due to malformed ASN.1 being
passed to any of the ASN1 methods of String.

Tested on linux/386 and darwin/amd64.

This fixes CVE-2020-7919 and was found thanks to the Project Wycheproof
test vectors.

Change-Id: I8c9696a8bfad1b40ec877cd740dba3467d66ab54
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/645211
Reviewed-by: Katie Hockman <katiehockman@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/647740
2020-01-24 22:56:46 +00:00
144 changed files with 5797 additions and 10563 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
# Add no patterns to .gitignore except for files generated by the build.
# Add no patterns to .hgignore except for files generated by the build.
last-change
+91 -240
View File
@@ -4,10 +4,7 @@
// Package acme provides an implementation of the
// Automatic Certificate Management Environment (ACME) spec.
// The intial implementation was based on ACME draft-02 and
// is now being extended to comply with RFC 8555.
// See https://tools.ietf.org/html/draft-ietf-acme-acme-02
// and https://tools.ietf.org/html/rfc8555 for details.
// See https://tools.ietf.org/html/draft-ietf-acme-acme-02 for details.
//
// Most common scenarios will want to use autocert subdirectory instead,
// which provides automatic access to certificates from Let's Encrypt
@@ -44,7 +41,7 @@ import (
const (
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
LetsEncryptURL = "https://acme-v02.api.letsencrypt.org/directory"
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.
@@ -55,16 +52,12 @@ const (
ALPNProto = "acme-tls/1"
)
// idPeACMEIdentifier is the OID for the ACME extension for the TLS-ALPN challenge.
// https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05#section-5.1
var idPeACMEIdentifier = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
// 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
maxCertSize = 1 << 20 // max size of a certificate, in DER bytes
// Used for decoding certs from application/pem-certificate-chain response,
// the default when in RFC mode.
maxCertChainSize = maxCertSize * maxChainLen
maxCertSize = 1 << 20 // max size of a certificate, in bytes
// Max number of collected nonces kept in memory.
// Expect usual peak of 1 or 2.
@@ -116,55 +109,21 @@ type Client struct {
// The jitter is a random value up to 1 second.
RetryBackoff func(n int, r *http.Request, resp *http.Response) time.Duration
// UserAgent is prepended to the User-Agent header sent to the ACME server,
// which by default is this package's name and version.
//
// Reusable libraries and tools in particular should set this value to be
// identifiable by the server, in case they are causing issues.
UserAgent string
cacheMu sync.Mutex
dir *Directory // cached result of Client's Discover method
kid keyID // cached Account.URI obtained from registerRFC or getAccountRFC
dirMu sync.Mutex // guards writes to dir
dir *Directory // cached result of Client's Discover method
noncesMu sync.Mutex
nonces map[string]struct{} // nonces collected from previous responses
}
// accountKID returns a key ID associated with c.Key, the account identity
// provided by the CA during RFC based registration.
// It assumes c.Discover has already been called.
//
// accountKID requires at most one network roundtrip.
// It caches only successful result.
//
// When in pre-RFC mode or when c.getRegRFC responds with an error, accountKID
// returns noKeyID.
func (c *Client) accountKID(ctx context.Context) keyID {
c.cacheMu.Lock()
defer c.cacheMu.Unlock()
if !c.dir.rfcCompliant() {
return noKeyID
}
if c.kid != noKeyID {
return c.kid
}
a, err := c.getRegRFC(ctx)
if err != nil {
return noKeyID
}
c.kid = keyID(a.URI)
return c.kid
}
// Discover performs ACME server discovery using c.DirectoryURL.
//
// It caches successful result. So, subsequent calls will not result in
// a network round-trip. This also means mutating c.DirectoryURL after successful call
// of this method will have no effect.
func (c *Client) Discover(ctx context.Context) (Directory, error) {
c.cacheMu.Lock()
defer c.cacheMu.Unlock()
c.dirMu.Lock()
defer c.dirMu.Unlock()
if c.dir != nil {
return *c.dir, nil
}
@@ -177,53 +136,27 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
c.addNonce(res.Header)
var v struct {
Reg string `json:"new-reg"`
RegRFC string `json:"newAccount"`
Authz string `json:"new-authz"`
AuthzRFC string `json:"newAuthz"`
OrderRFC string `json:"newOrder"`
Cert string `json:"new-cert"`
Revoke string `json:"revoke-cert"`
RevokeRFC string `json:"revokeCert"`
NonceRFC string `json:"newNonce"`
KeyChangeRFC string `json:"keyChange"`
Meta struct {
Terms string `json:"terms-of-service"`
TermsRFC string `json:"termsOfService"`
WebsiteRFC string `json:"website"`
CAA []string `json:"caa-identities"`
CAARFC []string `json:"caaIdentities"`
ExternalAcctRFC bool `json:"externalAccountRequired"`
Reg string `json:"new-reg"`
Authz string `json:"new-authz"`
Cert string `json:"new-cert"`
Revoke string `json:"revoke-cert"`
Meta struct {
Terms string `json:"terms-of-service"`
Website string `json:"website"`
CAA []string `json:"caa-identities"`
}
}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return Directory{}, err
}
if v.OrderRFC == "" {
// Non-RFC compliant ACME CA.
c.dir = &Directory{
RegURL: v.Reg,
AuthzURL: v.Authz,
CertURL: v.Cert,
RevokeURL: v.Revoke,
Terms: v.Meta.Terms,
Website: v.Meta.WebsiteRFC,
CAA: v.Meta.CAA,
}
return *c.dir, nil
}
// RFC compliant ACME CA.
c.dir = &Directory{
RegURL: v.RegRFC,
AuthzURL: v.AuthzRFC,
OrderURL: v.OrderRFC,
RevokeURL: v.RevokeRFC,
NonceURL: v.NonceRFC,
KeyChangeURL: v.KeyChangeRFC,
Terms: v.Meta.TermsRFC,
Website: v.Meta.WebsiteRFC,
CAA: v.Meta.CAARFC,
ExternalAccountRequired: v.Meta.ExternalAcctRFC,
RegURL: v.Reg,
AuthzURL: v.Authz,
CertURL: v.Cert,
RevokeURL: v.Revoke,
Terms: v.Meta.Terms,
Website: v.Meta.Website,
CAA: v.Meta.CAA,
}
return *c.dir, nil
}
@@ -236,9 +169,6 @@ func (c *Client) directoryURL() string {
}
// CreateCert requests a new certificate using the Certificate Signing Request csr encoded in DER format.
// It is incompatible with RFC 8555. Callers should use CreateOrderCert when interfacing
// with an RFC-compliant CA.
//
// The exp argument indicates the desired certificate validity duration. CA may issue a certificate
// with a different duration.
// If the bundle argument is true, the returned value will also contain the CA (issuer) certificate chain.
@@ -269,7 +199,7 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
req.NotAfter = now.Add(exp).Format(time.RFC3339)
}
res, err := c.post(ctx, nil, c.dir.CertURL, req, wantStatus(http.StatusCreated))
res, err := c.post(ctx, c.Key, c.dir.CertURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, "", err
}
@@ -290,22 +220,12 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
// It retries the request until the certificate is successfully retrieved,
// context is cancelled by the caller or an error response is received.
//
// If the bundle argument is true, the returned value also contains the CA (issuer)
// certificate chain.
// The returned value will also contain the CA (issuer) certificate if the bundle argument is true.
//
// FetchCert returns an error if the CA's response or chain was unreasonably large.
// 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) {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err
}
if dir.rfcCompliant() {
return c.fetchCertRFC(ctx, url, bundle)
}
// Legacy non-authenticated GET request.
res, err := c.get(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
@@ -320,15 +240,10 @@ func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]by
// For instance, the key pair of the certificate may be authorized.
// If the key is nil, c.Key is used instead.
func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
dir, err := c.Discover(ctx)
if err != nil {
if _, err := c.Discover(ctx); err != nil {
return err
}
if dir.rfcCompliant() {
return c.revokeCertRFC(ctx, key, cert, reason)
}
// Legacy CA.
body := &struct {
Resource string `json:"resource"`
Cert string `json:"certificate"`
@@ -338,7 +253,10 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte,
Cert: base64.RawURLEncoding.EncodeToString(cert),
Reason: int(reason),
}
res, err := c.post(ctx, key, dir.RevokeURL, body, wantStatus(http.StatusOK))
if key == nil {
key = c.Key
}
res, err := c.post(ctx, key, c.dir.RevokeURL, body, wantStatus(http.StatusOK))
if err != nil {
return err
}
@@ -350,30 +268,20 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte,
// during account registration. See Register method of Client for more details.
func AcceptTOS(tosURL string) bool { return true }
// Register creates a new account with the CA using c.Key.
// It returns the registered account. The account acct is not modified.
// Register creates a new account registration by following the "new-reg" flow.
// It returns the registered account. The account is not modified.
//
// The registration may require the caller to agree to the CA's Terms of Service (TOS).
// If so, and the account has not indicated the acceptance of the terms (see Account for details),
// Register calls prompt with a TOS URL provided by the CA. Prompt should report
// whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS.
//
// When interfacing with an RFC-compliant CA, non-RFC 8555 fields of acct are ignored
// and prompt is called if Directory's Terms field is non-zero.
// Also see Error's Instance field for when a CA requires already registered accounts to agree
// to an updated Terms of Service.
func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
dir, err := c.Discover(ctx)
if err != nil {
func (c *Client) Register(ctx context.Context, a *Account, prompt func(tosURL string) bool) (*Account, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
if dir.rfcCompliant() {
return c.registerRFC(ctx, acct, prompt)
}
// Legacy ACME draft registration flow.
a, err := c.doReg(ctx, dir.RegURL, "new-reg", acct)
if err != nil {
var err error
if a, err = c.doReg(ctx, c.dir.RegURL, "new-reg", a); err != nil {
return nil, err
}
var accept bool
@@ -387,20 +295,9 @@ func (c *Client) Register(ctx context.Context, acct *Account, prompt func(tosURL
return a, err
}
// GetReg retrieves an existing account associated with c.Key.
//
// The url argument is an Account URI used with pre-RFC 8555 CAs.
// It is ignored when interfacing with an RFC-compliant CA.
// GetReg retrieves an existing registration.
// The url argument is an Account URI.
func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err
}
if dir.rfcCompliant() {
return c.getRegRFC(ctx)
}
// Legacy CA.
a, err := c.doReg(ctx, url, "reg", nil)
if err != nil {
return nil, err
@@ -411,21 +308,9 @@ func (c *Client) GetReg(ctx context.Context, url string) (*Account, error) {
// UpdateReg updates an existing registration.
// It returns an updated account copy. The provided account is not modified.
//
// When interfacing with RFC-compliant CAs, a.URI is ignored and the account URL
// associated with c.Key is used instead.
func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error) {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err
}
if dir.rfcCompliant() {
return c.updateRegRFC(ctx, acct)
}
// Legacy CA.
uri := acct.URI
a, err := c.doReg(ctx, uri, "reg", acct)
func (c *Client) UpdateReg(ctx context.Context, a *Account) (*Account, error) {
uri := a.URI
a, err := c.doReg(ctx, uri, "reg", a)
if err != nil {
return nil, err
}
@@ -433,21 +318,13 @@ func (c *Client) UpdateReg(ctx context.Context, acct *Account) (*Account, error)
return a, nil
}
// Authorize performs the initial step in the pre-authorization flow,
// as opposed to order-based flow.
// Authorize performs the initial step in an authorization flow.
// The caller will then need to choose from and perform a set of returned
// challenges using c.Accept in order to successfully complete authorization.
//
// Once complete, the caller can use AuthorizeOrder which the CA
// should provision with the already satisfied authorization.
// For pre-RFC CAs, the caller can proceed directly to requesting a certificate
// using CreateCert method.
//
// If an authorization has been previously granted, the CA may return
// a valid authorization which has its Status field set to StatusValid.
//
// More about pre-authorization can be found at
// https://tools.ietf.org/html/rfc8555#section-7.4.1.
// a valid authorization (Authorization.Status is StatusValid). If so, the caller
// need not fulfill any challenge and can proceed to requesting a certificate.
func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization, error) {
return c.authorize(ctx, "dns", domain)
}
@@ -478,7 +355,7 @@ func (c *Client) authorize(ctx context.Context, typ, val string) (*Authorization
Resource: "new-authz",
Identifier: authzID{Type: typ, Value: val},
}
res, err := c.post(ctx, nil, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
res, err := c.post(ctx, c.Key, c.dir.AuthzURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, err
}
@@ -499,17 +376,7 @@ func (c *Client) authorize(ctx context.Context, typ, val 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) {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err
}
var res *http.Response
if dir.rfcCompliant() {
res, err = c.postAsGet(ctx, url, wantStatus(http.StatusOK))
} else {
res, err = c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
}
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
@@ -526,16 +393,11 @@ func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorizati
// The url argument is an Authorization.URI value.
//
// If successful, the caller will be required to obtain a new authorization
// using the Authorize or AuthorizeOrder methods before being able to request
// a new certificate for the domain associated with the authorization.
// using the Authorize method before being able to request a new certificate
// for the domain associated with the authorization.
//
// It does not revoke existing certificates.
func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
// Required for c.accountKID() when in RFC mode.
if _, err := c.Discover(ctx); err != nil {
return err
}
req := struct {
Resource string `json:"resource"`
Status string `json:"status"`
@@ -545,7 +407,7 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
Status: "deactivated",
Delete: true,
}
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
res, err := c.post(ctx, c.Key, url, req, wantStatus(http.StatusOK))
if err != nil {
return err
}
@@ -561,18 +423,8 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
// 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) {
// Required for c.accountKID() when in RFC mode.
dir, err := c.Discover(ctx)
if err != nil {
return nil, err
}
getfn := c.postAsGet
if !dir.rfcCompliant() {
getfn = c.get
}
for {
res, err := getfn(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
@@ -615,21 +467,10 @@ 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) {
// Required for c.accountKID() when in RFC mode.
dir, err := c.Discover(ctx)
res, err := c.get(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
getfn := c.postAsGet
if !dir.rfcCompliant() {
getfn = c.get
}
res, err := getfn(ctx, url, wantStatus(http.StatusOK, http.StatusAccepted))
if err != nil {
return nil, err
}
defer res.Body.Close()
v := wireChallenge{URI: url}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
@@ -643,29 +484,21 @@ func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, erro
//
// The server will then perform the validation asynchronously.
func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error) {
// Required for c.accountKID() when in RFC mode.
dir, err := c.Discover(ctx)
auth, err := keyAuth(c.Key.Public(), chal.Token)
if err != nil {
return nil, err
}
var req interface{} = json.RawMessage("{}") // RFC-compliant CA
if !dir.rfcCompliant() {
auth, err := keyAuth(c.Key.Public(), chal.Token)
if err != nil {
return nil, err
}
req = struct {
Resource string `json:"resource"`
Type string `json:"type"`
Auth string `json:"keyAuthorization"`
}{
Resource: "challenge",
Type: chal.Type,
Auth: auth,
}
req := struct {
Resource string `json:"resource"`
Type string `json:"type"`
Auth string `json:"keyAuthorization"`
}{
Resource: "challenge",
Type: chal.Type,
Auth: auth,
}
res, err := c.post(ctx, nil, chal.URI, req, wantStatus(
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)
))
@@ -715,8 +548,21 @@ func (c *Client) HTTP01ChallengePath(token string) string {
}
// TLSSNI01ChallengeCert creates a certificate for TLS-SNI-01 challenge response.
// Servers can present the certificate to validate the challenge and prove control
// over a domain name.
//
// Deprecated: This challenge type is unused in both draft-02 and RFC versions of ACME spec.
// The implementation is incomplete in that the returned value is a single certificate,
// computed only for Z0 of the key authorization. ACME CAs are expected to update
// their implementations to use the newer version, TLS-SNI-02.
// For more details on TLS-SNI-01 see https://tools.ietf.org/html/draft-ietf-acme-acme-01#section-7.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 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 {
@@ -733,8 +579,17 @@ func (c *Client) TLSSNI01ChallengeCert(token string, opt ...CertOption) (cert tl
}
// TLSSNI02ChallengeCert creates a certificate for TLS-SNI-02 challenge response.
// Servers can present the certificate to validate the challenge and prove control
// over a domain name. For more details on TLS-SNI-02 see
// https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.3.
//
// Deprecated: This challenge type is unused in both draft-02 and RFC versions of ACME spec.
// 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 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[:])
@@ -779,7 +634,7 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption)
return tls.Certificate{}, err
}
acmeExtension := pkix.Extension{
Id: idPeACMEIdentifier,
Id: idPeACMEIdentifierV1,
Critical: true,
Value: extValue,
}
@@ -801,7 +656,7 @@ func (c *Client) TLSALPN01ChallengeCert(token, domain string, opt ...CertOption)
return tlsChallengeCert([]string{domain}, newOpt)
}
// doReg sends all types of registration requests the old way (pre-RFC world).
// 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.
//
@@ -820,7 +675,7 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
req.Contact = acct.Contact
req.Agreement = acct.AgreedTerms
}
res, err := c.post(ctx, nil, url, req, wantStatus(
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
@@ -859,16 +714,12 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
}
// popNonce returns a nonce value previously stored with c.addNonce
// or fetches a fresh one from c.dir.NonceURL.
// If NonceURL is empty, it first tries c.directoryURL() and, failing that,
// the provided url.
// or fetches a fresh one from a URL by issuing a HEAD request.
// It first tries c.directoryURL() and then the provided url if the former fails.
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
c.noncesMu.Lock()
defer c.noncesMu.Unlock()
if len(c.nonces) == 0 {
if c.dir != nil && c.dir.NonceURL != "" {
return c.fetchNonce(ctx, c.dir.NonceURL)
}
dirURL := c.directoryURL()
v, err := c.fetchNonce(ctx, dirURL)
if err != nil && url != dirURL {
+40 -110
View File
@@ -16,7 +16,6 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
"math/big"
"net/http"
"net/http/httptest"
@@ -27,22 +26,12 @@ import (
"time"
)
// newTestClient creates a client with a non-nil Directory so that it skips
// the discovery which is otherwise done on the first call of almost every
// exported method.
func newTestClient() *Client {
return &Client{
Key: testKeyEC,
dir: &Directory{}, // skip discovery
}
}
// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
// interface.
func decodeJWSRequest(t *testing.T, v interface{}, r io.Reader) {
func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
// Decode request
var req struct{ Payload string }
if err := json.NewDecoder(r).Decode(&req); err != nil {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
t.Fatal(err)
}
payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
@@ -58,14 +47,12 @@ func decodeJWSRequest(t *testing.T, v interface{}, r io.Reader) {
type jwsHead struct {
Alg string
Nonce string
URL string `json:"url"`
KID string `json:"kid"`
JWK map[string]string `json:"jwk"`
}
func decodeJWSHead(r io.Reader) (*jwsHead, error) {
func decodeJWSHead(r *http.Request) (*jwsHead, error) {
var req struct{ Protected string }
if err := json.NewDecoder(r).Decode(&req); err != nil {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
return nil, err
}
b, err := base64.RawURLEncoding.DecodeString(req.Protected)
@@ -136,7 +123,7 @@ func TestRegister(t *testing.T) {
Contact []string
Agreement string
}
decodeJWSRequest(t, &j, r.Body)
decodeJWSRequest(t, &j, r)
// Test request
if j.Resource != "new-reg" {
@@ -206,7 +193,7 @@ func TestUpdateReg(t *testing.T) {
Contact []string
Agreement string
}
decodeJWSRequest(t, &j, r.Body)
decodeJWSRequest(t, &j, r)
// Test request
if j.Resource != "reg" {
@@ -228,11 +215,7 @@ func TestUpdateReg(t *testing.T) {
}))
defer ts.Close()
c := Client{
Key: testKeyEC,
DirectoryURL: ts.URL, // don't dial outside of localhost
dir: &Directory{}, // don't do discovery
}
c := Client{Key: testKeyEC}
a := &Account{URI: ts.URL, Contact: contacts, AgreedTerms: terms}
var err error
if a, err = c.UpdateReg(context.Background(), a); err != nil {
@@ -271,7 +254,7 @@ func TestGetReg(t *testing.T) {
Contact []string
Agreement string
}
decodeJWSRequest(t, &j, r.Body)
decodeJWSRequest(t, &j, r)
// Test request
if j.Resource != "reg" {
@@ -293,11 +276,7 @@ func TestGetReg(t *testing.T) {
}))
defer ts.Close()
c := Client{
Key: testKeyEC,
DirectoryURL: ts.URL, // don't dial outside of localhost
dir: &Directory{}, // don't do discovery
}
c := Client{Key: testKeyEC}
a, err := c.GetReg(context.Background(), ts.URL)
if err != nil {
t.Fatal(err)
@@ -339,7 +318,7 @@ func TestAuthorize(t *testing.T) {
Value string
}
}
decodeJWSRequest(t, &j, r.Body)
decodeJWSRequest(t, &j, r)
// Test request
if j.Resource != "new-authz" {
@@ -494,7 +473,7 @@ func TestGetAuthorization(t *testing.T) {
}))
defer ts.Close()
cl := Client{Key: testKeyEC, DirectoryURL: ts.URL}
cl := Client{Key: testKeyEC}
auth, err := cl.GetAuthorization(context.Background(), ts.URL)
if err != nil {
t.Fatal(err)
@@ -569,45 +548,6 @@ func TestWaitAuthorization(t *testing.T) {
t.Errorf("err is %v (%T); want non-nil *AuthorizationError", err, err)
}
})
t.Run("invalid status with error returns the authorization error", func(t *testing.T) {
_, err := runWaitAuthorization(context.Background(), t, func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, `{
"type": "dns-01",
"status": "invalid",
"error": {
"type": "urn:ietf:params:acme:error:caa",
"detail": "CAA record for <domain> prevents issuance",
"status": 403
},
"url": "https://acme-v02.api.letsencrypt.org/acme/chall-v3/xxx/xxx",
"token": "xxx",
"validationRecord": [
{
"hostname": "<domain>"
}
]
}`)
})
want := &AuthorizationError{
Errors: []error{
(&wireError{
Status: 403,
Type: "urn:ietf:params:acme:error:caa",
Detail: "CAA record for <domain> prevents issuance",
}).error(nil),
},
}
_, ok := err.(*AuthorizationError)
if !ok {
t.Errorf("err is %T; want non-nil *AuthorizationError", err)
}
if err.Error() != want.Error() {
t.Errorf("err is %v; want %v", err, want)
}
})
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) {
@@ -663,7 +603,7 @@ func runWaitAuthorization(ctx context.Context, t *testing.T, h http.HandlerFunc)
}
ch := make(chan res, 1)
go func() {
var client = Client{DirectoryURL: ts.URL}
var client Client
a, err := client.WaitAuthorization(ctx, ts.URL)
ch <- res{a, err}
}()
@@ -689,7 +629,7 @@ func TestRevokeAuthorization(t *testing.T) {
Status string
Delete bool
}
decodeJWSRequest(t, &req, r.Body)
decodeJWSRequest(t, &req, r)
if req.Resource != "authz" {
t.Errorf("req.Resource = %q; want authz", req.Resource)
}
@@ -704,11 +644,7 @@ func TestRevokeAuthorization(t *testing.T) {
}
}))
defer ts.Close()
client := &Client{
Key: testKey,
DirectoryURL: ts.URL, // don't dial outside of localhost
dir: &Directory{}, // don't do discovery
}
client := &Client{Key: testKey}
ctx := context.Background()
if err := client.RevokeAuthorization(ctx, ts.URL+"/1"); err != nil {
t.Errorf("err = %v", err)
@@ -733,7 +669,7 @@ func TestPollChallenge(t *testing.T) {
}))
defer ts.Close()
cl := Client{Key: testKeyEC, DirectoryURL: ts.URL}
cl := Client{Key: testKeyEC}
chall, err := cl.GetChallenge(context.Background(), ts.URL)
if err != nil {
t.Fatal(err)
@@ -768,7 +704,7 @@ func TestAcceptChallenge(t *testing.T) {
Type string
Auth string `json:"keyAuthorization"`
}
decodeJWSRequest(t, &j, r.Body)
decodeJWSRequest(t, &j, r)
// Test request
if j.Resource != "challenge" {
@@ -794,11 +730,7 @@ func TestAcceptChallenge(t *testing.T) {
}))
defer ts.Close()
cl := Client{
Key: testKeyEC,
DirectoryURL: ts.URL, // don't dial outside of localhost
dir: &Directory{}, // don't do discovery
}
cl := Client{Key: testKeyEC}
c, err := cl.Accept(context.Background(), &Challenge{
URI: ts.URL,
Token: "token1",
@@ -839,7 +771,7 @@ func TestNewCert(t *testing.T) {
NotBefore string `json:"notBefore,omitempty"`
NotAfter string `json:"notAfter,omitempty"`
}
decodeJWSRequest(t, &j, r.Body)
decodeJWSRequest(t, &j, r)
// Test request
if j.Resource != "new-cert" {
@@ -914,8 +846,7 @@ func TestFetchCert(t *testing.T) {
w.Write([]byte{count})
}))
defer ts.Close()
cl := newTestClient()
res, err := cl.FetchCert(context.Background(), ts.URL, true)
res, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
if err != nil {
t.Fatalf("FetchCert: %v", err)
}
@@ -937,8 +868,7 @@ func TestFetchCertRetry(t *testing.T) {
w.Write([]byte{1})
}))
defer ts.Close()
cl := newTestClient()
res, err := cl.FetchCert(context.Background(), ts.URL, false)
res, err := (&Client{}).FetchCert(context.Background(), ts.URL, false)
if err != nil {
t.Fatalf("FetchCert: %v", err)
}
@@ -951,15 +881,14 @@ func TestFetchCertRetry(t *testing.T) {
func TestFetchCertCancel(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Retry-After", "0")
w.WriteHeader(http.StatusBadRequest)
w.WriteHeader(http.StatusAccepted)
}))
defer ts.Close()
ctx, cancel := context.WithCancel(context.Background())
done := make(chan struct{})
var err error
go func() {
cl := newTestClient()
_, err = cl.FetchCert(ctx, ts.URL, false)
_, err = (&Client{}).FetchCert(ctx, ts.URL, false)
close(done)
}()
cancel()
@@ -982,8 +911,7 @@ func TestFetchCertDepth(t *testing.T) {
w.Write([]byte{count})
}))
defer ts.Close()
cl := newTestClient()
_, err := cl.FetchCert(context.Background(), ts.URL, true)
_, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
if err == nil {
t.Errorf("err is nil")
}
@@ -998,8 +926,7 @@ func TestFetchCertBreadth(t *testing.T) {
w.Write([]byte{1})
}))
defer ts.Close()
cl := newTestClient()
_, err := cl.FetchCert(context.Background(), ts.URL, true)
_, err := (&Client{}).FetchCert(context.Background(), ts.URL, true)
if err == nil {
t.Errorf("err is nil")
}
@@ -1011,8 +938,7 @@ func TestFetchCertSize(t *testing.T) {
w.Write(b)
}))
defer ts.Close()
cl := newTestClient()
_, err := cl.FetchCert(context.Background(), ts.URL, false)
_, err := (&Client{}).FetchCert(context.Background(), ts.URL, false)
if err == nil {
t.Errorf("err is nil")
}
@@ -1030,7 +956,7 @@ func TestRevokeCert(t *testing.T) {
Certificate string
Reason int
}
decodeJWSRequest(t, &req, r.Body)
decodeJWSRequest(t, &req, r)
if req.Resource != "revoke-cert" {
t.Errorf("req.Resource = %q; want revoke-cert", req.Resource)
}
@@ -1097,7 +1023,7 @@ func TestNonce_fetch(t *testing.T) {
defer ts.Close()
for ; i < len(tests); i++ {
test := tests[i]
c := newTestClient()
c := &Client{}
n, err := c.fetchNonce(context.Background(), ts.URL)
if n != test.nonce {
t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
@@ -1116,7 +1042,7 @@ func TestNonce_fetchError(t *testing.T) {
w.WriteHeader(http.StatusTooManyRequests)
}))
defer ts.Close()
c := newTestClient()
c := &Client{}
_, err := c.fetchNonce(context.Background(), ts.URL)
e, ok := err.(*Error)
if !ok {
@@ -1191,7 +1117,7 @@ func TestNonce_postJWS(t *testing.T) {
w.Write([]byte(`{"status":"valid"}`))
}()
head, err := decodeJWSHead(r.Body)
head, err := decodeJWSHead(r)
if err != nil {
t.Errorf("decodeJWSHead: %v", err)
return
@@ -1263,7 +1189,8 @@ func TestTLSSNI01ChallengeCert(t *testing.T) {
san = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.acme.invalid"
)
tlscert, name, err := newTestClient().TLSSNI01ChallengeCert(token)
client := &Client{Key: testKeyEC}
tlscert, name, err := client.TLSSNI01ChallengeCert(token)
if err != nil {
t.Fatal(err)
}
@@ -1295,7 +1222,8 @@ func TestTLSSNI02ChallengeCert(t *testing.T) {
sanB = "dbbd5eefe7b4d06eb9d1d9f5acb4c7cd.a27d320e4b30332f0b6cb441734ad7b0.ka.acme.invalid"
)
tlscert, name, err := newTestClient().TLSSNI02ChallengeCert(token)
client := &Client{Key: testKeyEC}
tlscert, name, err := client.TLSSNI02ChallengeCert(token)
if err != nil {
t.Fatal(err)
}
@@ -1335,7 +1263,8 @@ func TestTLSALPN01ChallengeCert(t *testing.T) {
t.Fatal(err)
}
tlscert, err := newTestClient().TLSALPN01ChallengeCert(token, domain)
client := &Client{Key: testKeyEC}
tlscert, err := client.TLSALPN01ChallengeCert(token, domain)
if err != nil {
t.Fatal(err)
}
@@ -1356,7 +1285,7 @@ func TestTLSALPN01ChallengeCert(t *testing.T) {
}
acmeExts := []pkix.Extension{}
for _, ext := range cert.Extensions {
if idPeACMEIdentifier.Equal(ext.Id) {
if idPeACMEIdentifierV1.Equal(ext.Id) {
acmeExts = append(acmeExts, ext)
}
}
@@ -1384,7 +1313,7 @@ func TestTLSChallengeCertOpt(t *testing.T) {
}
opts := []CertOption{WithKey(key), WithTemplate(tmpl)}
client := newTestClient()
client := &Client{Key: testKeyEC}
cert1, _, err := client.TLSSNI01ChallengeCert("token", opts...)
if err != nil {
t.Fatal(err)
@@ -1442,7 +1371,7 @@ func TestHTTP01Challenge(t *testing.T) {
value = token + "." + testKeyECThumbprint
urlpath = "/.well-known/acme-challenge/" + token
)
client := newTestClient()
client := &Client{Key: testKeyEC}
val, err := client.HTTP01ChallengeResponse(token)
if err != nil {
t.Fatal(err)
@@ -1461,7 +1390,8 @@ func TestDNS01ChallengeRecord(t *testing.T) {
// base64 | tr -d '=' | tr '/+' '_-'
const value = "8DERMexQ5VcdJ_prpPiA0mVdp7imgbCgjsG4SqqNMIo"
val, err := newTestClient().DNS01ChallengeRecord("xxx")
client := &Client{Key: testKeyEC}
val, err := client.DNS01ChallengeRecord("xxx")
if err != nil {
t.Fatal(err)
}
+112 -205
View File
@@ -35,9 +35,6 @@ import (
"golang.org/x/net/idna"
)
// DefaultACMEDirectory is the default ACME Directory URL used when the Manager's Client is nil.
const DefaultACMEDirectory = "https://acme-v02.api.letsencrypt.org/directory"
// createCertRetryAfter is how much time to wait before removing a failed state
// entry due to an unsuccessful createCert call.
// This is a variable instead of a const for testing.
@@ -91,9 +88,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-alpn-01"
// or "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.
@@ -138,10 +135,9 @@ 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 DefaultACMEDirectory
// as the 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.
// If Client is nil, a zero-value acme.Client is used with acme.LetsEncryptURL
// 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
@@ -178,8 +174,8 @@ type Manager struct {
renewalMu sync.Mutex
renewal map[certKey]*domainRenewal
// challengeMu guards tryHTTP01, certTokens and httpTokens.
challengeMu sync.RWMutex
// tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens.
tokensMu sync.RWMutex
// tryHTTP01 indicates whether the Manager should try "http-01" challenge type
// during the authorization flow.
tryHTTP01 bool
@@ -188,11 +184,12 @@ 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-alpn-01 challenges
// and is keyed by the domain name which matches the ClientHello server name.
// 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 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
@@ -229,7 +226,7 @@ func (m *Manager) TLSConfig() *tls.Config {
// GetCertificate implements the tls.Config.GetCertificate hook.
// It provides a TLS certificate for hello.ServerName host, including answering
// tls-alpn-01 challenges.
// 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
@@ -238,7 +235,9 @@ func (m *Manager) TLSConfig() *tls.Config {
// 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.
// 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")
@@ -270,10 +269,13 @@ 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-ALPN challenge.
// Check whether this is a token cert requested for TLS-SNI or TLS-ALPN challenge.
if wantsTokenCert(hello) {
m.challengeMu.RLock()
defer m.challengeMu.RUnlock()
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
}
@@ -316,7 +318,8 @@ func wantsTokenCert(hello *tls.ClientHelloInfo) bool {
if len(hello.SupportedProtos) == 1 && hello.SupportedProtos[0] == acme.ALPNProto {
return true
}
return false
// tls-sni-xx
return strings.HasSuffix(hello.ServerName, ".acme.invalid")
}
func supportsECDSA(hello *tls.ClientHelloInfo) bool {
@@ -381,8 +384,8 @@ func supportsECDSA(hello *tls.ClientHelloInfo) bool {
// 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.challengeMu.Lock()
defer m.challengeMu.Unlock()
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
m.tryHTTP01 = true
if fallback == nil {
@@ -645,64 +648,71 @@ func (m *Manager) certState(ck certKey) (*certState, error) {
// 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, ck certKey) (der [][]byte, leaf *x509.Certificate, err error) {
csr, err := certRequest(key, ck.domain, m.ExtraExtensions)
if err != nil {
return nil, nil, err
}
client, err := m.acmeClient(ctx)
if err != nil {
return nil, nil, err
}
dir, err := client.Discover(ctx)
if err != nil {
return nil, nil, err
}
var chain [][]byte
switch {
// Pre-RFC legacy CA.
case dir.OrderURL == "":
if err := m.verify(ctx, client, ck.domain); err != nil {
return nil, nil, err
}
der, _, err := client.CreateCert(ctx, csr, 0, true)
if err != nil {
return nil, nil, err
}
chain = der
// RFC 8555 compliant CA.
default:
o, err := m.verifyRFC(ctx, client, ck.domain)
if err != nil {
return nil, nil, err
}
der, _, err := client.CreateOrderCert(ctx, o.FinalizeURL, csr, true)
if err != nil {
return nil, nil, err
}
chain = der
if err := m.verify(ctx, client, ck.domain); err != nil {
return nil, nil, err
}
leaf, err = validCert(ck, chain, key, m.now())
csr, err := certRequest(key, ck.domain, m.ExtraExtensions)
if err != nil {
return nil, nil, err
}
return chain, leaf, nil
der, _, err = client.CreateCert(ctx, csr, 0, true)
if err != nil {
return nil, nil, err
}
leaf, err = validCert(ck, der, key, m.now())
if err != nil {
return nil, nil, err
}
return der, leaf, nil
}
// verify runs the identifier (domain) pre-authorization flow for legacy CAs
// 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 {
// Remove all hanging authorizations to reduce rate limit quotas
// after we're done.
var authzURLs []string
// The list of challenge types we'll try to fulfill
// in this specific order.
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() {
go m.deactivatePendingAuthz(authzURLs)
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)
challengeTypes := m.supportedChallengeTypes()
var nextTyp int // challengeType index of the next challenge type to try
for {
// Start domain authorization and get the challenge.
@@ -710,7 +720,6 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
if err != nil {
return err
}
authzURLs = append(authzURLs, authz.URI)
// No point in accepting challenges if the authorization status
// is in a final state.
switch authz.Status {
@@ -720,6 +729,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) {
@@ -749,126 +760,11 @@ func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string
errs[chal] = err
continue
}
delete(pendingAuthzs, authz.URI)
return nil
}
}
// verifyRFC runs the identifier (domain) order-based authorization flow for RFC compliant CAs
// using each applicable ACME challenge type.
func (m *Manager) verifyRFC(ctx context.Context, client *acme.Client, domain string) (*acme.Order, error) {
// Try each supported challenge type starting with a new order each time.
// The nextTyp index of the next challenge type to try is shared across
// all order authorizations: if we've tried a challenge type once and it didn't work,
// it will most likely not work on another order's authorization either.
challengeTypes := m.supportedChallengeTypes()
nextTyp := 0 // challengeTypes index
AuthorizeOrderLoop:
for {
o, err := client.AuthorizeOrder(ctx, acme.DomainIDs(domain))
if err != nil {
return nil, err
}
// Remove all hanging authorizations to reduce rate limit quotas
// after we're done.
defer func(urls []string) {
go m.deactivatePendingAuthz(urls)
}(o.AuthzURLs)
// Check if there's actually anything we need to do.
switch o.Status {
case acme.StatusReady:
// Already authorized.
return o, nil
case acme.StatusPending:
// Continue normal Order-based flow.
default:
return nil, fmt.Errorf("acme/autocert: invalid new order status %q; order URL: %q", o.Status, o.URI)
}
// Satisfy all pending authorizations.
for _, zurl := range o.AuthzURLs {
z, err := client.GetAuthorization(ctx, zurl)
if err != nil {
return nil, err
}
if z.Status != acme.StatusPending {
// We are interested only in pending authorizations.
continue
}
// Pick the next preferred challenge.
var chal *acme.Challenge
for chal == nil && nextTyp < len(challengeTypes) {
chal = pickChallenge(challengeTypes[nextTyp], z.Challenges)
nextTyp++
}
if chal == nil {
return nil, fmt.Errorf("acme/autocert: unable to satisfy %q for domain %q: no viable challenge type found", z.URI, domain)
}
// Respond to the challenge and wait for validation result.
cleanup, err := m.fulfill(ctx, client, chal, domain)
if err != nil {
continue AuthorizeOrderLoop
}
defer cleanup()
if _, err := client.Accept(ctx, chal); err != nil {
continue AuthorizeOrderLoop
}
if _, err := client.WaitAuthorization(ctx, z.URI); err != nil {
continue AuthorizeOrderLoop
}
}
// All authorizations are satisfied.
// Wait for the CA to update the order status.
o, err = client.WaitOrder(ctx, o.URI)
if err != nil {
continue AuthorizeOrderLoop
}
return o, nil
}
}
func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
for _, c := range chal {
if c.Type == typ {
return c
}
}
return nil
}
func (m *Manager) supportedChallengeTypes() []string {
m.challengeMu.RLock()
defer m.challengeMu.RUnlock()
typ := []string{"tls-alpn-01"}
if m.tryHTTP01 {
typ = append(typ, "http-01")
}
return typ
}
// deactivatePendingAuthz relinquishes all authorizations identified by the elements
// of the provided uri slice which are in "pending" state.
// It ignores revocation errors.
//
// deactivatePendingAuthz takes no context argument and instead runs with its own
// "detached" context because deactivations are done in a goroutine separate from
// that of the main issuance or renewal flow.
func (m *Manager) deactivatePendingAuthz(uri []string) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
client, err := m.acmeClient(ctx)
if err != nil {
return
}
for _, u := range uri {
z, err := client.GetAuthorization(ctx, u)
if err == nil && z.Status == acme.StatusPending {
client.RevokeAuthorization(ctx, u)
}
}
}
// 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, domain string) (cleanup func(), err error) {
@@ -880,6 +776,20 @@ func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.C
}
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 {
return nil, err
}
m.putCertToken(ctx, name, &cert)
return func() { go m.deleteCertToken(name) }, nil
case "tls-sni-02":
cert, name, err := client.TLSSNI02ChallengeCert(chal.Token)
if err != nil {
return nil, err
}
m.putCertToken(ctx, name, &cert)
return func() { go m.deleteCertToken(name) }, nil
case "http-01":
resp, err := client.HTTP01ChallengeResponse(chal.Token)
if err != nil {
@@ -892,11 +802,20 @@ func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.C
return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
}
func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
for _, c := range chal {
if c.Type == typ {
return c
}
}
return nil
}
// 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.challengeMu.Lock()
defer m.challengeMu.Unlock()
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
if m.certTokens == nil {
m.certTokens = make(map[string]*tls.Certificate)
}
@@ -907,8 +826,8 @@ func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certi
// deleteCertToken removes the token certificate with the specified name
// from both m.certTokens map and m.Cache.
func (m *Manager) deleteCertToken(name string) {
m.challengeMu.Lock()
defer m.challengeMu.Unlock()
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
delete(m.certTokens, name)
if m.Cache != nil {
ck := certKey{domain: name, isToken: true}
@@ -919,8 +838,8 @@ func (m *Manager) deleteCertToken(name string) {
// httpToken retrieves an existing http-01 token value from an in-memory map
// or the optional cache.
func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) {
m.challengeMu.RLock()
defer m.challengeMu.RUnlock()
m.tokensMu.RLock()
defer m.tokensMu.RUnlock()
if v, ok := m.httpTokens[tokenPath]; ok {
return v, nil
}
@@ -935,8 +854,8 @@ func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, erro
//
// It ignores any error returned from Cache.Put.
func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) {
m.challengeMu.Lock()
defer m.challengeMu.Unlock()
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
if m.httpTokens == nil {
m.httpTokens = make(map[string][]byte)
}
@@ -952,8 +871,8 @@ func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) {
//
// If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout.
func (m *Manager) deleteHTTPToken(tokenPath string) {
m.challengeMu.Lock()
defer m.challengeMu.Unlock()
m.tokensMu.Lock()
defer m.tokensMu.Unlock()
delete(m.httpTokens, tokenPath)
if m.Cache != nil {
m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath))
@@ -1052,7 +971,7 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
client := m.Client
if client == nil {
client = &acme.Client{DirectoryURL: DefaultACMEDirectory}
client = &acme.Client{DirectoryURL: acme.LetsEncryptURL}
}
if client.Key == nil {
var err error
@@ -1061,32 +980,20 @@ func (m *Manager) acmeClient(ctx context.Context) (*acme.Client, error) {
return nil, err
}
}
if client.UserAgent == "" {
client.UserAgent = "autocert"
}
var contact []string
if m.Email != "" {
contact = []string{"mailto:" + m.Email}
}
a := &acme.Account{Contact: contact}
_, err := client.Register(ctx, a, m.Prompt)
if err == nil || isAccountAlreadyExist(err) {
if ae, ok := err.(*acme.Error); err == nil || ok && ae.StatusCode == http.StatusConflict {
// conflict indicates the key is already registered
m.client = client
err = nil
}
return m.client, err
}
// isAccountAlreadyExist reports whether the err, as returned from acme.Client.Register,
// indicates the account has already been registered.
func isAccountAlreadyExist(err error) bool {
if err == acme.ErrAccountAlreadyExists {
return true
}
ae, ok := err.(*acme.Error)
return ok && ae.StatusCode == http.StatusConflict
}
func (m *Manager) hostPolicy() HostPolicy {
if m.HostPolicy != nil {
return m.HostPolicy
+79 -99
View File
@@ -51,9 +51,14 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{
"status": "pending",
"challenges": [
{
"uri": "{{.}}/challenge/tls-alpn-01",
"type": "tls-alpn-01",
"token": "token-alpn"
"uri": "{{.}}/challenge/1",
"type": "tls-sni-01",
"token": "token-01"
},
{
"uri": "{{.}}/challenge/2",
"type": "tls-sni-02",
"token": "token-02"
},
{
"uri": "{{.}}/challenge/dns-01",
@@ -179,46 +184,28 @@ func decodePayload(v interface{}, r io.Reader) error {
return json.Unmarshal(payload, v)
}
type algorithmSupport int
const (
algRSA algorithmSupport = iota
algECDSA
)
func clientHelloInfo(sni string, alg algorithmSupport) *tls.ClientHelloInfo {
func clientHelloInfo(sni string, ecdsaSupport bool) *tls.ClientHelloInfo {
hello := &tls.ClientHelloInfo{
ServerName: sni,
CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
}
if alg == algECDSA {
if ecdsaSupport {
hello.CipherSuites = append(hello.CipherSuites, tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305)
}
return hello
}
// tokenCertFn returns a function suitable for startACMEServerStub.
// The returned function simulates a TLS hello request from a CA
// during validation of a tls-alpn-01 challenge.
func tokenCertFn(man *Manager, alg algorithmSupport) getCertificateFunc {
return func(sni string) (*tls.Certificate, error) {
hello := clientHelloInfo(sni, alg)
hello.SupportedProtos = []string{acme.ALPNProto}
return man.GetCertificate(hello)
}
}
func TestGetCertificate(t *testing.T) {
man := &Manager{Prompt: AcceptTOS}
defer man.stopRenew()
hello := clientHelloInfo("example.org", algECDSA)
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 := clientHelloInfo("example.org.", algECDSA)
hello := clientHelloInfo("example.org.", true)
testGetCertificate(t, man, "example.org", hello)
}
@@ -226,10 +213,10 @@ func TestGetCertificate_unicodeIDN(t *testing.T) {
man := &Manager{Prompt: AcceptTOS}
defer man.stopRenew()
hello := clientHelloInfo("σσσ.com", algECDSA)
hello := clientHelloInfo("σσσ.com", true)
testGetCertificate(t, man, "xn--4xaaa.com", hello)
hello = clientHelloInfo("σςΣ.com", algECDSA)
hello = clientHelloInfo("σςΣ.com", true)
testGetCertificate(t, man, "xn--4xaaa.com", hello)
}
@@ -237,10 +224,10 @@ func TestGetCertificate_mixedcase(t *testing.T) {
man := &Manager{Prompt: AcceptTOS}
defer man.stopRenew()
hello := clientHelloInfo("example.org", algECDSA)
hello := clientHelloInfo("example.org", true)
testGetCertificate(t, man, "example.org", hello)
hello = clientHelloInfo("EXAMPLE.ORG", algECDSA)
hello = clientHelloInfo("EXAMPLE.ORG", true)
testGetCertificate(t, man, "example.org", hello)
}
@@ -251,7 +238,7 @@ func TestGetCertificate_ForceRSA(t *testing.T) {
ForceRSA: true,
}
defer man.stopRenew()
hello := clientHelloInfo(exampleDomain, algECDSA)
hello := clientHelloInfo(exampleDomain, true)
testGetCertificate(t, man, exampleDomain, hello)
// ForceRSA was deprecated and is now ignored.
@@ -267,10 +254,10 @@ func TestGetCertificate_ForceRSA(t *testing.T) {
func TestGetCertificate_nilPrompt(t *testing.T) {
man := &Manager{}
defer man.stopRenew()
url, finish := startACMEServerStub(t, tokenCertFn(man, algECDSA), "example.org")
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org")
defer finish()
man.Client = &acme.Client{DirectoryURL: url}
hello := clientHelloInfo("example.org", algECDSA)
hello := clientHelloInfo("example.org", true)
if _, err := man.GetCertificate(hello); err == nil {
t.Error("got certificate for example.org; wanted error")
}
@@ -304,7 +291,7 @@ func TestGetCertificate_expiredCache(t *testing.T) {
// The expired cached cert should trigger a new cert issuance
// and return without an error.
hello := clientHelloInfo(exampleDomain, algECDSA)
hello := clientHelloInfo(exampleDomain, true)
testGetCertificate(t, man, exampleDomain, hello)
}
@@ -336,7 +323,7 @@ func TestGetCertificate_failedAttempt(t *testing.T) {
},
}
defer man.stopRenew()
hello := clientHelloInfo(exampleDomain, algECDSA)
hello := clientHelloInfo(exampleDomain, true)
if _, err := man.GetCertificate(hello); err == nil {
t.Error("GetCertificate: err is nil")
}
@@ -353,9 +340,9 @@ func TestGetCertificate_failedAttempt(t *testing.T) {
}
// testGetCertificate_tokenCache tests the fallback of token certificate fetches
// to cache when Manager.certTokens misses.
// algorithmSupport refers to the CA when verifying the certificate token.
func testGetCertificate_tokenCache(t *testing.T, tokenAlg algorithmSupport) {
// 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,
@@ -369,11 +356,10 @@ func testGetCertificate_tokenCache(t *testing.T, tokenAlg algorithmSupport) {
// Send the verification request to a different Manager from the one that
// initiated the authorization, when they share caches.
url, finish := startACMEServerStub(t, tokenCertFn(man2, tokenAlg), "example.org")
url, finish := startACMEServerStub(t, getCertificateFromManager(man2, ecdsaSupport), "example.org")
defer finish()
man1.Client = &acme.Client{DirectoryURL: url}
man2.Client = &acme.Client{DirectoryURL: url}
hello := clientHelloInfo("example.org", algECDSA)
hello := clientHelloInfo("example.org", true)
if _, err := man1.GetCertificate(hello); err != nil {
t.Error(err)
}
@@ -384,10 +370,10 @@ func testGetCertificate_tokenCache(t *testing.T, tokenAlg algorithmSupport) {
func TestGetCertificate_tokenCache(t *testing.T) {
t.Run("ecdsaSupport=true", func(t *testing.T) {
testGetCertificate_tokenCache(t, algECDSA)
testGetCertificate_tokenCache(t, true)
})
t.Run("ecdsaSupport=false", func(t *testing.T) {
testGetCertificate_tokenCache(t, algRSA)
testGetCertificate_tokenCache(t, false)
})
}
@@ -395,30 +381,30 @@ func TestGetCertificate_ecdsaVsRSA(t *testing.T) {
cache := newMemCache(t)
man := &Manager{Prompt: AcceptTOS, Cache: cache}
defer man.stopRenew()
url, finish := startACMEServerStub(t, tokenCertFn(man, algECDSA), "example.org")
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), "example.org")
defer finish()
man.Client = &acme.Client{DirectoryURL: url}
cert, err := man.GetCertificate(clientHelloInfo("example.org", algECDSA))
cert, err := man.GetCertificate(clientHelloInfo("example.org", true))
if err != nil {
t.Fatal(err)
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", algRSA))
cert, err = man.GetCertificate(clientHelloInfo("example.org", false))
if err != nil {
t.Fatal(err)
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", algECDSA)); err != nil {
if _, err := man.GetCertificate(clientHelloInfo("example.org", true)); err != nil {
t.Error(err)
}
if _, err := man.GetCertificate(clientHelloInfo("example.org", algRSA)); err != nil {
if _, err := man.GetCertificate(clientHelloInfo("example.org", false)); err != nil {
t.Error(err)
}
if numCerts := cache.numCerts(); numCerts != 2 {
@@ -430,7 +416,7 @@ func TestGetCertificate_wrongCacheKeyType(t *testing.T) {
cache := newMemCache(t)
man := &Manager{Prompt: AcceptTOS, Cache: cache}
defer man.stopRenew()
url, finish := startACMEServerStub(t, tokenCertFn(man, algECDSA), exampleDomain)
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), exampleDomain)
defer finish()
man.Client = &acme.Client{DirectoryURL: url}
@@ -457,9 +443,9 @@ func TestGetCertificate_wrongCacheKeyType(t *testing.T) {
}
// The RSA cached cert should be silently ignored and replaced.
cert, err := man.GetCertificate(clientHelloInfo(exampleDomain, algECDSA))
cert, err := man.GetCertificate(clientHelloInfo(exampleDomain, true))
if err != nil {
t.Fatal(err)
t.Error(err)
}
if _, ok := cert.Leaf.PublicKey.(*ecdsa.PublicKey); !ok {
t.Error("an ECDSA client was served a non-ECDSA certificate")
@@ -469,35 +455,25 @@ func TestGetCertificate_wrongCacheKeyType(t *testing.T) {
}
}
type getCertificateFunc func(domain string) (*tls.Certificate, error)
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.
// TODO: Drop this in favour of x/crypto/acme/autocert/internal/acmetest.
func startACMEServerStub(t *testing.T, tokenCert getCertificateFunc, domain string) (url string, finish func()) {
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() {
tlscert, err := tokenCert(domain)
if err != nil {
t.Errorf("verifyTokenCert: tokenCert(%q): %v", domain, err)
if err := getCertificate(tokenCertName); err != nil {
t.Errorf("verifyTokenCert: GetCertificate(%q): %v", tokenCertName, err)
return
}
crt, err := x509.ParseCertificate(tlscert.Certificate[0])
if err != nil {
t.Errorf("verifyTokenCert: x509.ParseCertificate: %v", err)
}
if err := crt.VerifyHostname(domain); err != nil {
t.Errorf("verifyTokenCert: %v", err)
}
// See https://tools.ietf.org/html/draft-ietf-acme-tls-alpn-05#section-5.1
oid := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 31}
for _, x := range crt.Extensions {
if x.Id.Equal(oid) {
// No need to check the extension value here.
// This is done in acme package tests.
return
}
}
t.Error("verifyTokenCert: no id-pe-acmeIdentifier extension found")
}
// ACME CA server stub
@@ -525,8 +501,8 @@ func startACMEServerStub(t *testing.T, tokenCert getCertificateFunc, domain stri
if err := authzTmpl.Execute(w, ca.URL); err != nil {
t.Errorf("authzTmpl: %v", err)
}
// accept tls-alpn-01 challenge
case "/challenge/tls-alpn-01":
// accept tls-sni-02 challenge
case "/challenge/2":
verifyTokenCert()
w.Write([]byte("{}"))
// authorization status
@@ -576,7 +552,7 @@ func startACMEServerStub(t *testing.T, tokenCert getCertificateFunc, domain stri
tick := time.NewTicker(100 * time.Millisecond)
defer tick.Stop()
for {
if _, err := tokenCert(domain); err != nil {
if err := getCertificate(tokenCertName); err != nil {
return
}
select {
@@ -600,7 +576,7 @@ func startACMEServerStub(t *testing.T, tokenCert getCertificateFunc, domain stri
// 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, tokenCertFn(man, algECDSA), domain)
url, finish := startACMEServerStub(t, getCertificateFromManager(man, true), domain)
defer finish()
man.Client = &acme.Client{DirectoryURL: url}
@@ -682,8 +658,11 @@ func TestVerifyHTTP01(t *testing.T) {
if err := authzTmpl.Execute(w, ca.URL); err != nil {
t.Errorf("authzTmpl: %v", err)
}
// Reject tls-alpn-01.
case "/challenge/tls-alpn-01":
// Accept tls-sni-02.
case "/challenge/2":
w.Write([]byte("{}"))
// Reject tls-sni-01.
case "/challenge/1":
http.Error(w, "won't accept tls-sni-01", http.StatusBadRequest)
// Should not accept dns-01.
case "/challenge/dns-01":
@@ -695,9 +674,10 @@ func TestVerifyHTTP01(t *testing.T) {
verifyHTTPToken()
w.Write([]byte("{}"))
// Authorization statuses.
case "/authz/1": // tls-alpn-01
// Make tls-sni-xxx invalid.
case "/authz/1", "/authz/2":
w.Write([]byte(`{"status": "invalid"}`))
case "/authz/2": // http-01
case "/authz/3", "/authz/4":
w.Write([]byte(`{"status": "valid"}`))
default:
http.NotFound(w, r)
@@ -720,10 +700,10 @@ func TestVerifyHTTP01(t *testing.T) {
if err := m.verify(ctx, client, "example.org"); err != nil {
t.Errorf("m.verify: %v", err)
}
// Only tls-alpn-01 and http-01 must be accepted.
// Only tls-sni-01, tls-sni-02 and http-01 must be accepted
// The dns-01 challenge is unsupported.
if authzCount != 2 {
t.Errorf("authzCount = %d; want 2", authzCount)
if authzCount != 3 {
t.Errorf("authzCount = %d; want 3", authzCount)
}
if !didAcceptHTTP01 {
t.Error("did not accept http-01 challenge")
@@ -736,8 +716,8 @@ func TestRevokeFailedAuthz(t *testing.T) {
// 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-alpn-01
"/authz/1": false, // http-01
"/authz/0": false, // tls-sni-02
"/authz/1": false, // tls-sni-01
"/authz/2": false, // no viable challenge, but authz is created
}
@@ -772,15 +752,14 @@ func TestRevokeFailedAuthz(t *testing.T) {
t.Errorf("authzTmpl: %v", err)
}
authzCount++
// tls-alpn-01 challenge "accept" request.
case "/challenge/tls-alpn-01":
// tls-sni-02 challenge "accept" request.
case "/challenge/2":
// Refuse.
http.Error(w, "won't accept tls-alpn-01 challenge", http.StatusBadRequest)
// http-01 challenge "accept" request.
case "/challenge/http-01":
// Refuse.
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(`{"status":"invalid"}`))
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.
@@ -804,7 +783,8 @@ func TestRevokeFailedAuthz(t *testing.T) {
return
}
// Authorization status requests.
w.Write([]byte(`{"status":"pending"}`))
// 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)
@@ -815,9 +795,8 @@ func TestRevokeFailedAuthz(t *testing.T) {
m := &Manager{
Client: &acme.Client{DirectoryURL: ca.URL},
}
m.HTTPHandler(nil) // enable http-01 challenge type
// Should fail and revoke 3 authorizations.
// The first 2 are tls-alpn-01 and http-01 challenges.
// 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 {
@@ -1079,7 +1058,7 @@ func TestManagerGetCertificateBogusSNI(t *testing.T) {
{"fo.o", "cache.Get of fo.o"},
}
for _, tt := range tests {
_, err := m.GetCertificate(clientHelloInfo(tt.name, algECDSA))
_, 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)
@@ -1219,6 +1198,7 @@ func TestEndToEnd(t *testing.T) {
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()
+1 -7
View File
@@ -77,7 +77,6 @@ func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
if tmp, err = d.writeTempFile(name, data); err != nil {
return
}
defer os.Remove(tmp)
select {
case <-ctx.Done():
// Don't overwrite the file if the context was canceled.
@@ -117,17 +116,12 @@ func (d DirCache) Delete(ctx context.Context, name string) error {
}
// writeTempFile writes b to a temporary file, closes the file and returns its path.
func (d DirCache) writeTempFile(prefix string, b []byte) (name string, reterr error) {
func (d DirCache) writeTempFile(prefix string, b []byte) (string, error) {
// TempFile uses 0600 permissions
f, err := ioutil.TempFile(string(d), prefix)
if err != nil {
return "", err
}
defer func() {
if reterr != nil {
os.Remove(f.Name())
}
}()
if _, err := f.Write(b); err != nil {
f.Close()
return "", err
-9
View File
@@ -48,15 +48,6 @@ func TestDirCache(t *testing.T) {
t.Error(err)
}
// test put deletes temp file
tmp, err := filepath.Glob(name + "?*")
if err != nil {
t.Error(err)
}
if tmp != nil {
t.Errorf("temp file exists: %s", tmp)
}
// test delete
if err := cache.Delete(ctx, "dummy"); err != nil {
t.Fatalf("delete: %v", err)
+93 -229
View File
@@ -17,21 +17,15 @@ import (
"crypto/x509/pkix"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"io"
"log"
"math/big"
"net/http"
"net/http/httptest"
"path"
"sort"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/crypto/acme"
)
// CAServer is a simple test server which implements ACME spec bits needed for testing.
@@ -51,7 +45,6 @@ type CAServer struct {
certCount int // number of issued certs
domainAddr map[string]string // domain name to addr:port resolution
authorizations map[string]*authorization // keyed by domain name
orders []*order // index is used as order ID
errors []error // encountered client errors
}
@@ -90,7 +83,7 @@ func NewCAServer(challengeTypes []string, domainsWhitelist []string) *CAServer {
NotAfter: time.Now().Add(365 * 24 * time.Hour),
KeyUsage: x509.KeyUsageCertSign,
BasicConstraintsValid: true,
IsCA: true,
IsCA: true,
}
der, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key)
if err != nil {
@@ -117,24 +110,11 @@ func (ca *CAServer) Close() {
ca.server.Close()
}
func (ca *CAServer) serverURL(format string, arg ...interface{}) string {
return ca.server.URL + fmt.Sprintf(format, arg...)
}
func (ca *CAServer) addr(domain string) (string, error) {
// Errors returns all client errors.
func (ca *CAServer) Errors() []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) httpErrorf(w http.ResponseWriter, code int, format string, a ...interface{}) {
s := fmt.Sprintf(format, a...)
log.Println(s)
http.Error(w, s, code)
return ca.errors
}
// Resolve adds a domain to address resolution for the ca to dial to
@@ -146,10 +126,9 @@ func (ca *CAServer) Resolve(domain, addr string) {
}
type discovery struct {
NewNonce string `json:"newNonce"`
NewReg string `json:"newAccount"`
NewOrder string `json:"newOrder"`
NewAuthz string `json:"newAuthz"`
NewReg string `json:"new-reg"`
NewAuthz string `json:"new-authz"`
NewCert string `json:"new-cert"`
}
type challenge struct {
@@ -162,117 +141,98 @@ type authorization struct {
Status string `json:"status"`
Challenges []challenge `json:"challenges"`
id int
domain string
}
type order struct {
Status string `json:"status"`
AuthzURLs []string `json:"authorizations"`
FinalizeURL string `json:"finalize"` // CSR submit URL
CertURL string `json:"certificate"` // already issued cert
leaf []byte // issued cert in DER format
}
func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL)
w.Header().Set("Replay-Nonce", "nonce")
if r.Method == "HEAD" {
// a nonce request
return
}
// TODO: Verify nonce header for all POST requests.
switch {
default:
ca.httpErrorf(w, http.StatusBadRequest, "unrecognized r.URL.Path: %s", r.URL.Path)
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{
NewNonce: ca.serverURL("/new-nonce"),
NewReg: ca.serverURL("/new-reg"),
NewOrder: ca.serverURL("/new-order"),
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))
}
// Nonce requests.
case r.URL.Path == "/new-nonce":
// Nonce values are always set. Nothing else to do.
return
// Client key registration request.
case r.URL.Path == "/new-reg":
// TODO: Check the user account key against a ca.accountKeys?
w.Header().Set("Location", ca.serverURL("/accounts/1"))
w.WriteHeader(http.StatusCreated)
w.Write([]byte("{}"))
// New order request.
case r.URL.Path == "/new-order":
var req struct {
Identifiers []struct{ Value string }
}
if err := decodePayload(&req, r.Body); err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
return
}
ca.mu.Lock()
defer ca.mu.Unlock()
o := &order{Status: acme.StatusPending}
for _, id := range req.Identifiers {
z := ca.authz(id.Value)
o.AuthzURLs = append(o.AuthzURLs, ca.serverURL("/authz/%s", z.domain))
}
orderID := len(ca.orders)
ca.orders = append(ca.orders, o)
w.Header().Set("Location", ca.serverURL("/orders/%d", orderID))
w.WriteHeader(http.StatusCreated)
if err := json.NewEncoder(w).Encode(o); err != nil {
panic(err)
}
// Existing order status requests.
case strings.HasPrefix(r.URL.Path, "/orders/"):
ca.mu.Lock()
defer ca.mu.Unlock()
o, err := ca.storedOrder(strings.TrimPrefix(r.URL.Path, "/orders/"))
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
return
}
if err := json.NewEncoder(w).Encode(o); err != nil {
panic(err)
}
// Identifier authorization request.
// 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.httpErrorf(w, http.StatusBadRequest, err.Error())
ca.addError(err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
ca.mu.Lock()
defer ca.mu.Unlock()
z := ca.authz(req.Identifier.Value)
w.Header().Set("Location", ca.serverURL("/authz/%s", z.domain))
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(z); err != nil {
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()
_, exist := ca.authorizations[domain]
ca.mu.Unlock()
if !exist {
ca.httpErrorf(w, http.StatusBadRequest, "challenge accept: no authz for %q", domain)
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 ca.validateChallenge("tls-alpn-01", domain)
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.
@@ -282,28 +242,15 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
defer ca.mu.Unlock()
authz, ok := ca.authorizations[domain]
if !ok {
ca.httpErrorf(w, http.StatusNotFound, "no authz for %q", domain)
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))
}
// Certificate issuance request.
case strings.HasPrefix(r.URL.Path, "/new-cert/"):
ca.mu.Lock()
defer ca.mu.Unlock()
orderID := strings.TrimPrefix(r.URL.Path, "/new-cert/")
o, err := ca.storedOrder(orderID)
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
return
}
if o.Status != acme.StatusReady {
ca.httpErrorf(w, http.StatusForbidden, "order status: %s", o.Status)
return
}
// Validate CSR request.
// Cert issuance request.
case r.URL.Path == "/new-cert":
var req struct {
CSR string `json:"csr"`
}
@@ -311,52 +258,47 @@ func (ca *CAServer) handle(w http.ResponseWriter, r *http.Request) {
b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
csr, err := x509.ParseCertificateRequest(b)
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
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.httpErrorf(w, http.StatusUnauthorized, err.Error())
ca.addError(err)
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
if err := ca.authorized(names); err != nil {
ca.httpErrorf(w, http.StatusUnauthorized, err.Error())
ca.addError(err)
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
// Issue the certificate.
der, err := ca.leafCert(csr)
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, "new-cert response: ca.leafCert: %v", err)
return
}
o.leaf = der
o.CertURL = ca.serverURL("/issued-cert/%s", orderID)
o.Status = acme.StatusValid
if err := json.NewEncoder(w).Encode(o); err != nil {
panic(err)
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)
// Already issued cert download requests.
case strings.HasPrefix(r.URL.Path, "/issued-cert/"):
ca.mu.Lock()
defer ca.mu.Unlock()
o, err := ca.storedOrder(strings.TrimPrefix(r.URL.Path, "/issued-cert/"))
if err != nil {
ca.httpErrorf(w, http.StatusBadRequest, err.Error())
return
}
if o.Status != acme.StatusValid {
ca.httpErrorf(w, http.StatusForbidden, "order status: %s", o.Status)
return
}
w.Header().Set("Content-Type", "application/pem-certificate-chain")
pem.Encode(w, &pem.Block{Type: "CERTIFICATE", Bytes: o.leaf})
pem.Encode(w, &pem.Block{Type: "CERTIFICATE", Bytes: ca.rootCert})
// CA chain cert request.
case r.URL.Path == "/ca-cert":
w.Write(ca.rootCert)
}
}
// matchWhitelist reports whether all dnsNames are whitelisted.
// The whitelist is provided in NewCAServer.
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
@@ -374,50 +316,13 @@ func (ca *CAServer) matchWhitelist(dnsNames []string) error {
return nil
}
// storedOrder retrieves a previously created order at index i.
// It requires ca.mu to be locked.
func (ca *CAServer) storedOrder(i string) (*order, error) {
idx, err := strconv.Atoi(i)
if err != nil {
return nil, fmt.Errorf("storedOrder: %v", err)
}
if idx < 0 {
return nil, fmt.Errorf("storedOrder: invalid order index %d", idx)
}
if idx > len(ca.orders)-1 {
return nil, fmt.Errorf("storedOrder: no such order %d", idx)
}
return ca.orders[idx], nil
}
// authz returns an existing authorization for the identifier or creates a new one.
// It requires ca.mu to be locked.
func (ca *CAServer) authz(identifier string) *authorization {
authz, ok := ca.authorizations[identifier]
if !ok {
authz = &authorization{
domain: identifier,
Status: acme.StatusPending,
}
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
}
return authz
}
// authorized reports whether all authorizations for dnsNames have been satisfied.
// It requires ca.mu to be locked.
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 != acme.StatusValid {
if !ok || authz.Status != "valid" {
noauthz = append(noauthz, name)
}
}
@@ -427,9 +332,9 @@ func (ca *CAServer) authorized(dnsNames []string) error {
return nil
}
// leafCert issues a new certificate.
// It requires ca.mu to be locked.
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)),
@@ -447,55 +352,14 @@ func (ca *CAServer) leafCert(csr *x509.CertificateRequest) (der []byte, err erro
return x509.CreateCertificate(rand.Reader, leaf, ca.rootTemplate, csr.PublicKey, ca.rootKey)
}
// TODO: Only tls-alpn-01 is currently supported: implement http-01 and dns-01.
func (ca *CAServer) validateChallenge(typ, identifier string) {
var err error
switch typ {
case "tls-alpn-01":
err = ca.verifyALPNChallenge(identifier)
default:
panic(fmt.Sprintf("validation of %q is not implemented", typ))
}
func (ca *CAServer) addr(domain string) (string, error) {
ca.mu.Lock()
defer ca.mu.Unlock()
authz := ca.authorizations[identifier]
if err != nil {
authz.Status = "invalid"
} else {
authz.Status = "valid"
}
log.Printf("validated %q for %q; authz status is now: %s", typ, identifier, authz.Status)
// Update all pending orders.
// An order becomes "ready" if all authorizations are "valid".
// An order becomes "invalid" if any authorization is "invalid".
// Status changes: https://tools.ietf.org/html/rfc8555#section-7.1.6
OrdersLoop:
for i, o := range ca.orders {
if o.Status != acme.StatusPending {
continue
}
var countValid int
for _, zurl := range o.AuthzURLs {
z, ok := ca.authorizations[path.Base(zurl)]
if !ok {
log.Printf("no authz %q for order %d", zurl, i)
continue OrdersLoop
}
if z.Status == acme.StatusInvalid {
o.Status = acme.StatusInvalid
log.Printf("order %d is now invalid", i)
continue OrdersLoop
}
if z.Status == acme.StatusValid {
countValid++
}
}
if countValid == len(o.AuthzURLs) {
o.Status = acme.StatusReady
o.FinalizeURL = ca.serverURL("/new-cert/%d", i)
log.Printf("order %d is now ready", i)
}
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 {
+2
View File
@@ -72,6 +72,7 @@ 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: m.TLSConfig(),
}
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
@@ -79,6 +80,7 @@ func (m *Manager) Listener() net.Listener {
}
type listener struct {
m *Manager
conf *tls.Config
tcpListener net.Listener
+3 -6
View File
@@ -71,9 +71,6 @@ func TestRenewFromCache(t *testing.T) {
w.Header().Set("Location", ca.URL+"/authz/1")
w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"status": "valid"}`))
// authorization status request done by Manager's revokePendingAuthz.
case "/authz/1":
w.Write([]byte(`{"status": "valid"}`))
// cert request
case "/new-cert":
var req struct {
@@ -176,7 +173,7 @@ func TestRenewFromCache(t *testing.T) {
}
// trigger renew
hello := clientHelloInfo(exampleDomain, algECDSA)
hello := clientHelloInfo(exampleDomain, true)
if _, err := man.GetCertificate(hello); err != nil {
t.Fatal(err)
}
@@ -302,7 +299,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
}
// assert the expiring cert is returned from state
hello := clientHelloInfo(exampleDomain, algECDSA)
hello := clientHelloInfo(exampleDomain, true)
tlscert, err := man.GetCertificate(hello)
if err != nil {
t.Fatal(err)
@@ -320,7 +317,7 @@ func TestRenewFromCacheAlreadyRenewed(t *testing.T) {
t.Fatal("renew took too long to occur")
case <-done:
// assert the new cert is returned from state after renew
hello := clientHelloInfo(exampleDomain, algECDSA)
hello := clientHelloInfo(exampleDomain, true)
tlscert, err := man.GetCertificate(hello)
if err != nil {
t.Fatal(err)
+3 -43
View File
@@ -155,16 +155,8 @@ func (c *Client) get(ctx context.Context, url string, ok resOkay) (*http.Respons
}
}
// postAsGet is POST-as-GET, a replacement for GET in RFC8555
// as described in https://tools.ietf.org/html/rfc8555#section-6.3.
// It makes a POST request in KID form with zero JWS payload.
// See nopayload doc comments in jws.go.
func (c *Client) postAsGet(ctx context.Context, url string, ok resOkay) (*http.Response, error) {
return c.post(ctx, nil, url, noPayload, ok)
}
// post issues a signed POST request in JWS format using the provided key
// to the specified URL. If key is nil, c.Key is used instead.
// to the specified URL.
// It returns a non-error value only when ok reports true.
//
// post retries unsuccessful attempts according to c.RetryBackoff
@@ -201,28 +193,14 @@ func (c *Client) post(ctx context.Context, key crypto.Signer, url string, body i
}
// postNoRetry signs the body with the given key and POSTs it to the provided url.
// It is used by c.post to retry unsuccessful attempts.
// The body argument must be JSON-serializable.
//
// If key argument is nil, c.Key is used to sign the request.
// If key argument is nil and c.accountKID returns a non-zero keyID,
// the request is sent in KID form. Otherwise, JWK form is used.
//
// In practice, when interfacing with RFC-compliant CAs most requests are sent in KID form
// and JWK is used only when KID is unavailable: new account endpoint and certificate
// revocation requests authenticated by a cert key.
// See jwsEncodeJSON for other details.
// 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) {
kid := noKeyID
if key == nil {
key = c.Key
kid = c.accountKID(ctx)
}
nonce, err := c.popNonce(ctx, url)
if err != nil {
return nil, nil, err
}
b, err := jwsEncodeJSON(body, key, kid, nonce, url)
b, err := jwsEncodeJSON(body, key, nonce)
if err != nil {
return nil, nil, err
}
@@ -241,7 +219,6 @@ func (c *Client) postNoRetry(ctx context.Context, key crypto.Signer, url string,
// 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) {
req.Header.Set("User-Agent", c.userAgent())
res, err := c.httpClient().Do(req.WithContext(ctx))
if err != nil {
select {
@@ -266,23 +243,6 @@ func (c *Client) httpClient() *http.Client {
return http.DefaultClient
}
// packageVersion is the version of the module that contains this package, for
// sending as part of the User-Agent header. It's set in version_go112.go.
var packageVersion string
// userAgent returns the User-Agent header value. It includes the package name,
// the module version (if available), and the c.UserAgent value (if set).
func (c *Client) userAgent() string {
ua := "golang.org/x/crypto/acme"
if packageVersion != "" {
ua += "@" + packageVersion
}
if c.UserAgent != "" {
ua = c.UserAgent + " " + ua
}
return ua
}
// 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.
+1 -28
View File
@@ -87,7 +87,7 @@ func TestPostWithRetries(t *testing.T) {
return
}
head, err := decodeJWSHead(r.Body)
head, err := decodeJWSHead(r)
switch {
case err != nil:
t.Errorf("decodeJWSHead: %v", err)
@@ -211,30 +211,3 @@ func TestRetryBackoffArgs(t *testing.T) {
t.Errorf("nretry = %d; want 3", nretry)
}
}
func TestUserAgent(t *testing.T) {
for _, custom := range []string{"", "CUSTOM_UA"} {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Log(r.UserAgent())
if s := "golang.org/x/crypto/acme"; !strings.Contains(r.UserAgent(), s) {
t.Errorf("expected User-Agent to contain %q, got %q", s, r.UserAgent())
}
if !strings.Contains(r.UserAgent(), custom) {
t.Errorf("expected User-Agent to contain %q, got %q", custom, r.UserAgent())
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{}`))
}))
defer ts.Close()
client := &Client{
Key: testKey,
DirectoryURL: ts.URL,
UserAgent: custom,
}
if _, err := client.Discover(context.Background()); err != nil {
t.Errorf("client.Discover: %v", err)
}
}
}
-480
View File
@@ -1,480 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The acmeprober program runs against an actual ACME CA implementation.
// It spins up an HTTP server to fulfill authorization challenges
// or execute a DNS script to provision a response to dns-01 challenge.
//
// For http-01 and tls-alpn-01 challenge types this requires the ACME CA
// to be able to reach the HTTP server.
//
// A usage example:
//
// go run prober.go \
// -d https://acme-staging-v02.api.letsencrypt.org/directory \
// -f order \
// -t http-01 \
// -a :8080 \
// -domain some.example.org
//
// The above assumes a TCP tunnel from some.example.org:80 to 0.0.0.0:8080
// in order for the test to be able to fulfill http-01 challenge.
// To test tls-alpn-01 challenge, 443 port would need to be tunneled
// to 0.0.0.0:8080.
// When running with dns-01 challenge type, use -s argument instead of -a.
package main
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"os/exec"
"strings"
"time"
"golang.org/x/crypto/acme"
)
var (
// ACME CA directory URL.
// Let's Encrypt v1 prod: https://acme-v01.api.letsencrypt.org/directory
// Let's Encrypt v2 prod: https://acme-v02.api.letsencrypt.org/directory
// Let's Encrypt v2 staging: https://acme-staging-v02.api.letsencrypt.org/directory
// See the following for more CAs implementing ACME protocol:
// https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment#CAs_&_PKIs_that_offer_ACME_certificates
directory = flag.String("d", "", "ACME directory URL.")
reginfo = flag.String("r", "", "ACME account registration info.")
flow = flag.String("f", "", "Flow to run: order, preauthz (RFC8555) or preauthz02 (draft-02).")
chaltyp = flag.String("t", "", "Challenge type: tls-alpn-01, http-01 or dns-01.")
addr = flag.String("a", "", "Local server address for tls-alpn-01 and http-01.")
dnsscript = flag.String("s", "", "Script to run for provisioning dns-01 challenges.")
domain = flag.String("domain", "", "Space separate domain identifiers.")
ipaddr = flag.String("ip", "", "Space separate IP address identifiers.")
)
func main() {
flag.Usage = func() {
fmt.Fprintln(flag.CommandLine.Output(), `
The prober program runs against an actual ACME CA implementation.
It spins up an HTTP server to fulfill authorization challenges
or execute a DNS script to provision a response to dns-01 challenge.
For http-01 and tls-alpn-01 challenge types this requires the ACME CA
to be able to reach the HTTP server.
A usage example:
go run prober.go \
-d https://acme-staging-v02.api.letsencrypt.org/directory \
-f order \
-t http-01 \
-a :8080 \
-domain some.example.org
The above assumes a TCP tunnel from some.example.org:80 to 0.0.0.0:8080
in order for the test to be able to fulfill http-01 challenge.
To test tls-alpn-01 challenge, 443 port would need to be tunneled
to 0.0.0.0:8080.
When running with dns-01 challenge type, use -s argument instead of -a.
`)
flag.PrintDefaults()
}
flag.Parse()
identifiers := acme.DomainIDs(strings.Fields(*domain)...)
identifiers = append(identifiers, acme.IPIDs(strings.Fields(*ipaddr)...)...)
if len(identifiers) == 0 {
log.Fatal("at least one domain or IP addr identifier is required")
}
// Duration of the whole run.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
// Create and register a new account.
akey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatal(err)
}
cl := &acme.Client{Key: akey, DirectoryURL: *directory}
a := &acme.Account{Contact: strings.Fields(*reginfo)}
if _, err := cl.Register(ctx, a, acme.AcceptTOS); err != nil {
log.Fatalf("Register: %v", err)
}
// Run the desired flow test.
p := &prober{
client: cl,
chalType: *chaltyp,
localAddr: *addr,
dnsScript: *dnsscript,
}
switch *flow {
case "order":
p.runOrder(ctx, identifiers)
case "preauthz":
p.runPreauthz(ctx, identifiers)
case "preauthz02":
p.runPreauthzLegacy(ctx, identifiers)
default:
log.Fatalf("unknown flow: %q", *flow)
}
if len(p.errors) > 0 {
os.Exit(1)
}
}
type prober struct {
client *acme.Client
chalType string
localAddr string
dnsScript string
errors []error
}
func (p *prober) errorf(format string, a ...interface{}) {
err := fmt.Errorf(format, a...)
log.Print(err)
p.errors = append(p.errors, err)
}
func (p *prober) runOrder(ctx context.Context, identifiers []acme.AuthzID) {
// Create a new order and pick a challenge.
// Note that Let's Encrypt will reply with 400 error:malformed
// "NotBefore and NotAfter are not supported" when providing a NotAfter
// value like WithOrderNotAfter(time.Now().Add(24 * time.Hour)).
o, err := p.client.AuthorizeOrder(ctx, identifiers)
if err != nil {
log.Fatalf("AuthorizeOrder: %v", err)
}
var zurls []string
for _, u := range o.AuthzURLs {
z, err := p.client.GetAuthorization(ctx, u)
if err != nil {
log.Fatalf("GetAuthorization(%q): %v", u, err)
}
log.Printf("%+v", z)
if z.Status != acme.StatusPending {
log.Printf("authz status is %q; skipping", z.Status)
continue
}
if err := p.fulfill(ctx, z); err != nil {
log.Fatalf("fulfill(%s): %v", z.URI, err)
}
zurls = append(zurls, z.URI)
log.Printf("authorized for %+v", z.Identifier)
}
log.Print("all challenges are done")
if _, err := p.client.WaitOrder(ctx, o.URI); err != nil {
log.Fatalf("WaitOrder(%q): %v", o.URI, err)
}
csr, certkey := newCSR(identifiers)
der, curl, err := p.client.CreateOrderCert(ctx, o.FinalizeURL, csr, true)
if err != nil {
log.Fatalf("CreateOrderCert: %v", err)
}
log.Printf("cert URL: %s", curl)
if err := checkCert(der, identifiers); err != nil {
p.errorf("invalid cert: %v", err)
}
// Deactivate all authorizations we satisfied earlier.
for _, v := range zurls {
if err := p.client.RevokeAuthorization(ctx, v); err != nil {
p.errorf("RevokAuthorization(%q): %v", v, err)
continue
}
}
// Deactivate the account. We don't need it for any further calls.
if err := p.client.DeactivateReg(ctx); err != nil {
p.errorf("DeactivateReg: %v", err)
}
// Try revoking the issued cert using its private key.
if err := p.client.RevokeCert(ctx, certkey, der[0], acme.CRLReasonCessationOfOperation); err != nil {
p.errorf("RevokeCert: %v", err)
}
}
func (p *prober) runPreauthz(ctx context.Context, identifiers []acme.AuthzID) {
dir, err := p.client.Discover(ctx)
if err != nil {
log.Fatalf("Discover: %v", err)
}
if dir.AuthzURL == "" {
log.Fatal("CA does not support pre-authorization")
}
var zurls []string
for _, id := range identifiers {
z, err := authorize(ctx, p.client, id)
if err != nil {
log.Fatalf("AuthorizeID(%+v): %v", z, err)
}
if z.Status == acme.StatusValid {
log.Printf("authz %s is valid; skipping", z.URI)
continue
}
if err := p.fulfill(ctx, z); err != nil {
log.Fatalf("fulfill(%s): %v", z.URI, err)
}
zurls = append(zurls, z.URI)
log.Printf("authorized for %+v", id)
}
// We should be all set now.
// Expect all authorizations to be satisfied.
log.Print("all challenges are done")
o, err := p.client.AuthorizeOrder(ctx, identifiers)
if err != nil {
log.Fatalf("AuthorizeOrder: %v", err)
}
waitCtx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
if _, err := p.client.WaitOrder(waitCtx, o.URI); err != nil {
log.Fatalf("WaitOrder(%q): %v", o.URI, err)
}
csr, certkey := newCSR(identifiers)
der, curl, err := p.client.CreateOrderCert(ctx, o.FinalizeURL, csr, true)
if err != nil {
log.Fatalf("CreateOrderCert: %v", err)
}
log.Printf("cert URL: %s", curl)
if err := checkCert(der, identifiers); err != nil {
p.errorf("invalid cert: %v", err)
}
// Deactivate all authorizations we satisfied earlier.
for _, v := range zurls {
if err := p.client.RevokeAuthorization(ctx, v); err != nil {
p.errorf("RevokeAuthorization(%q): %v", v, err)
continue
}
}
// Deactivate the account. We don't need it for any further calls.
if err := p.client.DeactivateReg(ctx); err != nil {
p.errorf("DeactivateReg: %v", err)
}
// Try revoking the issued cert using its private key.
if err := p.client.RevokeCert(ctx, certkey, der[0], acme.CRLReasonCessationOfOperation); err != nil {
p.errorf("RevokeCert: %v", err)
}
}
func (p *prober) runPreauthzLegacy(ctx context.Context, identifiers []acme.AuthzID) {
var zurls []string
for _, id := range identifiers {
z, err := authorize(ctx, p.client, id)
if err != nil {
log.Fatalf("AuthorizeID(%+v): %v", id, err)
}
if z.Status == acme.StatusValid {
log.Printf("authz %s is valid; skipping", z.URI)
continue
}
if err := p.fulfill(ctx, z); err != nil {
log.Fatalf("fulfill(%s): %v", z.URI, err)
}
zurls = append(zurls, z.URI)
log.Printf("authorized for %+v", id)
}
// We should be all set now.
log.Print("all authorizations are done")
csr, certkey := newCSR(identifiers)
der, curl, err := p.client.CreateCert(ctx, csr, 48*time.Hour, true)
if err != nil {
log.Fatalf("CreateCert: %v", err)
}
log.Printf("cert URL: %s", curl)
if err := checkCert(der, identifiers); err != nil {
p.errorf("invalid cert: %v", err)
}
// Deactivate all authorizations we satisfied earlier.
for _, v := range zurls {
if err := p.client.RevokeAuthorization(ctx, v); err != nil {
p.errorf("RevokAuthorization(%q): %v", v, err)
continue
}
}
// Try revoking the issued cert using its private key.
if err := p.client.RevokeCert(ctx, certkey, der[0], acme.CRLReasonCessationOfOperation); err != nil {
p.errorf("RevokeCert: %v", err)
}
}
func (p *prober) fulfill(ctx context.Context, z *acme.Authorization) error {
var chal *acme.Challenge
for i, c := range z.Challenges {
log.Printf("challenge %d: %+v", i, c)
if c.Type == p.chalType {
log.Printf("picked %s for authz %s", c.URI, z.URI)
chal = c
}
}
if chal == nil {
return fmt.Errorf("challenge type %q wasn't offered for authz %s", p.chalType, z.URI)
}
switch chal.Type {
case "tls-alpn-01":
return p.runTLSALPN01(ctx, z, chal)
case "http-01":
return p.runHTTP01(ctx, z, chal)
case "dns-01":
return p.runDNS01(ctx, z, chal)
default:
return fmt.Errorf("unknown challenge type %q", chal.Type)
}
}
func (p *prober) runTLSALPN01(ctx context.Context, z *acme.Authorization, chal *acme.Challenge) error {
tokenCert, err := p.client.TLSALPN01ChallengeCert(chal.Token, z.Identifier.Value)
if err != nil {
return fmt.Errorf("TLSALPN01ChallengeCert: %v", err)
}
s := &http.Server{
Addr: p.localAddr,
TLSConfig: &tls.Config{
NextProtos: []string{acme.ALPNProto},
GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
log.Printf("hello: %+v", hello)
return &tokenCert, nil
},
},
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL)
w.WriteHeader(http.StatusNotFound)
}),
}
go s.ListenAndServeTLS("", "")
defer s.Close()
if _, err := p.client.Accept(ctx, chal); err != nil {
return fmt.Errorf("Accept(%q): %v", chal.URI, err)
}
_, zerr := p.client.WaitAuthorization(ctx, z.URI)
return zerr
}
func (p *prober) runHTTP01(ctx context.Context, z *acme.Authorization, chal *acme.Challenge) error {
body, err := p.client.HTTP01ChallengeResponse(chal.Token)
if err != nil {
return fmt.Errorf("HTTP01ChallengeResponse: %v", err)
}
s := &http.Server{
Addr: p.localAddr,
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s %s", r.Method, r.URL)
if r.URL.Path != p.client.HTTP01ChallengePath(chal.Token) {
w.WriteHeader(http.StatusNotFound)
return
}
w.Write([]byte(body))
}),
}
go s.ListenAndServe()
defer s.Close()
if _, err := p.client.Accept(ctx, chal); err != nil {
return fmt.Errorf("Accept(%q): %v", chal.URI, err)
}
_, zerr := p.client.WaitAuthorization(ctx, z.URI)
return zerr
}
func (p *prober) runDNS01(ctx context.Context, z *acme.Authorization, chal *acme.Challenge) error {
token, err := p.client.DNS01ChallengeRecord(chal.Token)
if err != nil {
return fmt.Errorf("DNS01ChallengeRecord: %v", err)
}
name := fmt.Sprintf("_acme-challenge.%s", z.Identifier.Value)
cmd := exec.CommandContext(ctx, p.dnsScript, name, token)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return fmt.Errorf("%s: %v", p.dnsScript, err)
}
if _, err := p.client.Accept(ctx, chal); err != nil {
return fmt.Errorf("Accept(%q): %v", chal.URI, err)
}
_, zerr := p.client.WaitAuthorization(ctx, z.URI)
return zerr
}
func authorize(ctx context.Context, client *acme.Client, id acme.AuthzID) (*acme.Authorization, error) {
if id.Type == "ip" {
return client.AuthorizeIP(ctx, id.Value)
}
return client.Authorize(ctx, id.Value)
}
func checkCert(derChain [][]byte, id []acme.AuthzID) error {
if len(derChain) == 0 {
return errors.New("cert chain is zero bytes")
}
for i, b := range derChain {
crt, err := x509.ParseCertificate(b)
if err != nil {
return fmt.Errorf("%d: ParseCertificate: %v", i, err)
}
log.Printf("%d: serial: 0x%s", i, crt.SerialNumber)
log.Printf("%d: subject: %s", i, crt.Subject)
log.Printf("%d: issuer: %s", i, crt.Issuer)
log.Printf("%d: expires in %.1f day(s)", i, time.Until(crt.NotAfter).Hours()/24)
if i > 0 { // not a leaf cert
continue
}
p := &pem.Block{Type: "CERTIFICATE", Bytes: b}
log.Printf("%d: leaf:\n%s", i, pem.EncodeToMemory(p))
for _, v := range id {
if err := crt.VerifyHostname(v.Value); err != nil {
return err
}
}
}
return nil
}
func newCSR(identifiers []acme.AuthzID) ([]byte, crypto.Signer) {
var csr x509.CertificateRequest
for _, id := range identifiers {
switch id.Type {
case "dns":
csr.DNSNames = append(csr.DNSNames, id.Value)
case "ip":
csr.IPAddresses = append(csr.IPAddresses, net.ParseIP(id.Value))
default:
panic(fmt.Sprintf("newCSR: unknown identifier type %q", id.Type))
}
}
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
panic(fmt.Sprintf("newCSR: ecdsa.GenerateKey for a cert: %v", err))
}
b, err := x509.CreateCertificateRequest(rand.Reader, &csr, k)
if err != nil {
panic(fmt.Sprintf("newCSR: x509.CreateCertificateRequest: %v", err))
}
return b, k
}
+23 -54
View File
@@ -11,60 +11,31 @@ import (
"crypto/rsa"
"crypto/sha256"
_ "crypto/sha512" // need for EC keys
"encoding/asn1"
"encoding/base64"
"encoding/json"
"fmt"
"math/big"
)
// keyID is the account identity provided by a CA during registration.
type keyID string
// noKeyID indicates that jwsEncodeJSON should compute and use JWK instead of a KID.
// See jwsEncodeJSON for details.
const noKeyID = keyID("")
// noPayload indicates jwsEncodeJSON will encode zero-length octet string
// in a JWS request. This is called POST-as-GET in RFC 8555 and is used to make
// authenticated GET requests via POSTing with an empty payload.
// See https://tools.ietf.org/html/rfc8555#section-6.3 for more details.
const noPayload = ""
// jwsEncodeJSON signs claimset using provided key and a nonce.
// The result is serialized in JSON format containing either kid or jwk
// fields based on the provided keyID value.
//
// If kid is non-empty, its quoted value is inserted in the protected head
// as "kid" field value. Otherwise, JWK is computed using jwkEncode and inserted
// as "jwk" field value. The "jwk" and "kid" fields are mutually exclusive.
//
// The result is serialized in JSON format.
// See https://tools.ietf.org/html/rfc7515#section-7.
func jwsEncodeJSON(claimset interface{}, key crypto.Signer, kid keyID, nonce, url string) ([]byte, error) {
func jwsEncodeJSON(claimset interface{}, key crypto.Signer, nonce string) ([]byte, error) {
jwk, err := jwkEncode(key.Public())
if err != nil {
return nil, err
}
alg, sha := jwsHasher(key.Public())
if alg == "" || !sha.Available() {
return nil, ErrUnsupportedKey
}
var phead string
switch kid {
case noKeyID:
jwk, err := jwkEncode(key.Public())
if err != nil {
return nil, err
}
phead = fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q,"url":%q}`, alg, jwk, nonce, url)
default:
phead = fmt.Sprintf(`{"alg":%q,"kid":%q,"nonce":%q,"url":%q}`, alg, kid, nonce, url)
}
phead := fmt.Sprintf(`{"alg":%q,"jwk":%s,"nonce":%q}`, alg, jwk, nonce)
phead = base64.RawURLEncoding.EncodeToString([]byte(phead))
var payload string
if claimset != noPayload {
cs, err := json.Marshal(claimset)
if err != nil {
return nil, err
}
payload = base64.RawURLEncoding.EncodeToString(cs)
cs, err := json.Marshal(claimset)
if err != nil {
return nil, err
}
payload := base64.RawURLEncoding.EncodeToString(cs)
hash := sha.New()
hash.Write([]byte(phead + "." + payload))
sig, err := jwsSign(key, sha, hash.Sum(nil))
@@ -127,23 +98,21 @@ func jwkEncode(pub crypto.PublicKey) (string, error) {
// jwsSign signs the digest using the given key.
// 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 pub := key.Public().(type) {
case *rsa.PublicKey:
return key.Sign(rand.Reader, digest, hash)
case *ecdsa.PublicKey:
sigASN1, err := key.Sign(rand.Reader, digest, hash)
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
}
var rs struct{ R, S *big.Int }
if _, err := asn1.Unmarshal(sigASN1, &rs); err != nil {
return nil, err
}
rb, sb := rs.R.Bytes(), rs.S.Bytes()
size := pub.Params().BitSize / 8
rb, sb := r.Bytes(), s.Bytes()
size := key.Params().BitSize / 8
if size%8 > 0 {
size++
}
@@ -152,7 +121,7 @@ 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
+35 -110
View File
@@ -9,7 +9,6 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
@@ -20,18 +19,7 @@ import (
"testing"
)
// The following shell command alias is used in the comments
// throughout this file:
// alias b64raw="base64 -w0 | tr -d '=' | tr '/+' '_-'"
const (
// Modulus in raw base64:
// 4xgZ3eRPkwoRvy7qeRUbmMDe0V-xH9eWLdu0iheeLlrmD2mqWXfP9IeSKApbn34
// g8TuAS9g5zhq8ELQ3kmjr-KV86GAMgI6VAcGlq3QrzpTCf_30Ab7-zawrfRaFON
// a1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosqEXeaIkVYBEhbh
// Nu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZfoyFyek380mHg
// JAumQ_I2fjj98_97mk3ihOY4AgVdCDj1z_GCoZkG5Rq7nbCGyosyKWyDX00Zs-n
// NqVhoLeIvXC4nnWdJMZ6rogxyQQ
testKeyPEM = `
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
@@ -94,7 +82,7 @@ GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
`
// 1. openssl ec -in key.pem -noout -text
// 2. remove first byte, 04 (the header); the rest is X and Y
// 3. convert each with: echo <val> | xxd -r -p | b64raw
// 3. convert each with: echo <val> | xxd -r -p | base64 -w 100 | tr -d '=' | tr '/+' '_-'
testKeyECPubX = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
testKeyECPubY = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
testKeyEC384PubX = "MyrY_jLNLx6E1-Xc79_y-WDFzlriOVCkYyYoKWoWAqlw9gQNY9BP9sbeb5T3_oJt"
@@ -103,7 +91,7 @@ GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax"
// echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
// openssl dgst -binary -sha256 | b64raw
// openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-'
testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
)
@@ -152,7 +140,7 @@ func TestJWSEncodeJSON(t *testing.T) {
// JWS signed with testKey and "nonce" as the nonce value
// JSON-serialized JWS fields are split for easier testing
const (
// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce","url":"url"}
// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"}
protected = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
"IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
"SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
@@ -163,20 +151,19 @@ func TestJWSEncodeJSON(t *testing.T) {
"bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
"ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
"b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
"UVEifSwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
"UVEifSwibm9uY2UiOiJub25jZSJ9"
// {"Msg":"Hello JWS"}
payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
// printf '<protected>.<payload>' | openssl dgst -binary -sha256 -sign testKey | b64raw
signature = "YFyl_xz1E7TR-3E1bIuASTr424EgCvBHjt25WUFC2VaDjXYV0Rj_" +
"Hd3dJ_2IRqBrXDZZ2n4ZeA_4mm3QFwmwyeDwe2sWElhb82lCZ8iX" +
"uFnjeOmSOjx-nWwPa5ibCXzLq13zZ-OBV1Z4oN_TuailQeRoSfA3" +
"nO8gG52mv1x2OMQ5MAFtt8jcngBLzts4AyhI6mBJ2w7Yaj3ZCriq" +
"DWA3GLFvvHdW1Ba9Z01wtGT2CuZI7DUk_6Qj1b3BkBGcoKur5C9i" +
"bUJtCkABwBMvBQNyD3MmXsrRFRTgvVlyU_yMaucYm7nmzEr_2PaQ" +
"50rFt_9qOfJ4sfbLtG1Wwae57BQx1g"
payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
signature = "eAGUikStX_UxyiFhxSLMyuyBcIB80GeBkFROCpap2sW3EmkU_ggF" +
"knaQzxrTfItICSAXsCLIquZ5BbrSWA_4vdEYrwWtdUj7NqFKjHRa" +
"zpLHcoR7r1rEHvkoP1xj49lS5fc3Wjjq8JUhffkhGbWZ8ZVkgPdC" +
"4tMBWiQDoth-x8jELP_3LYOB_ScUXi2mETBawLgOT2K8rA0Vbbmx" +
"hWNlOWuUf-8hL5YX4IOEwsS8JK_TrTq5Zc9My0zHJmaieqDV0UlP" +
"k0onFjPFkGm7MrPSgd0MqRG-4vSAg2O4hDo7rKv4n8POjjXlNQvM" +
"9IPLr8qZ7usYBKhEGwX3yq_eicAwBw"
)
b, err := jwsEncodeJSON(claims, testKey, noKeyID, "nonce", "url")
b, err := jwsEncodeJSON(claims, testKey, "nonce")
if err != nil {
t.Fatal(err)
}
@@ -195,46 +182,6 @@ func TestJWSEncodeJSON(t *testing.T) {
}
}
func TestJWSEncodeKID(t *testing.T) {
kid := keyID("https://example.org/account/1")
claims := struct{ Msg string }{"Hello JWS"}
// JWS signed with testKeyEC
const (
// {"alg":"ES256","kid":"https://example.org/account/1","nonce":"nonce","url":"url"}
protected = "eyJhbGciOiJFUzI1NiIsImtpZCI6Imh0dHBzOi8vZXhhbXBsZS5" +
"vcmcvYWNjb3VudC8xIiwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
// {"Msg":"Hello JWS"}
payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
)
b, err := jwsEncodeJSON(claims, testKeyEC, kid, "nonce", "url")
if err != nil {
t.Fatal(err)
}
var jws struct{ Protected, Payload, Signature string }
if err := json.Unmarshal(b, &jws); err != nil {
t.Fatal(err)
}
if jws.Protected != protected {
t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
}
if jws.Payload != payload {
t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
}
sig, err := base64.RawURLEncoding.DecodeString(jws.Signature)
if err != nil {
t.Fatalf("jws.Signature: %v", err)
}
r, s := big.NewInt(0), big.NewInt(0)
r.SetBytes(sig[:len(sig)/2])
s.SetBytes(sig[len(sig)/2:])
h := sha256.Sum256([]byte(protected + "." + payload))
if !ecdsa.Verify(testKeyEC.Public().(*ecdsa.PublicKey), h[:], r, s) {
t.Error("invalid signature")
}
}
func TestJWSEncodeJSONEC(t *testing.T) {
tt := []struct {
key *ecdsa.PrivateKey
@@ -247,7 +194,7 @@ func TestJWSEncodeJSONEC(t *testing.T) {
}
for i, test := range tt {
claims := struct{ Msg string }{"Hello JWS"}
b, err := jwsEncodeJSON(claims, test.key, noKeyID, "nonce", "url")
b, err := jwsEncodeJSON(claims, test.key, "nonce")
if err != nil {
t.Errorf("%d: %v", i, err)
continue
@@ -265,8 +212,6 @@ func TestJWSEncodeJSONEC(t *testing.T) {
var head struct {
Alg string
Nonce string
URL string `json:"url"`
KID string `json:"kid"`
JWK struct {
Crv string
Kty string
@@ -283,13 +228,6 @@ func TestJWSEncodeJSONEC(t *testing.T) {
if head.Nonce != "nonce" {
t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce)
}
if head.URL != "url" {
t.Errorf("%d: head.URL = %q; want 'url'", i, head.URL)
}
if head.KID != "" {
// We used noKeyID in jwsEncodeJSON: expect no kid value.
t.Errorf("%d: head.KID = %q; want empty", i, head.KID)
}
if head.JWK.Crv != test.crv {
t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv)
}
@@ -318,27 +256,18 @@ func (s *customTestSigner) Sign(io.Reader, []byte, crypto.SignerOpts) ([]byte, e
func TestJWSEncodeJSONCustom(t *testing.T) {
claims := struct{ Msg string }{"hello"}
const (
// printf '{"Msg":"hello"}' | b64raw
// printf '{"Msg":"hello"}' | base64 | tr -d '=' | tr '/+' '_-'
payload = "eyJNc2ciOiJoZWxsbyJ9"
// printf 'testsig' | b64raw
// printf 'testsig' | base64 | tr -d '='
testsig = "dGVzdHNpZw"
// the example P256 curve point from https://tools.ietf.org/html/rfc7515#appendix-A.3.1
// encoded as ASN.1…
es256stdsig = "MEUCIA7RIVN5Y2xIPC9/FVgH1AKjsigDOvl8fheBmsMWnqZlAiEA" +
"xQoH04w8cOXY8S2vCEpUgKZlkMXyk1Cajz9/ioOjVNU"
// …and RFC7518 (https://tools.ietf.org/html/rfc7518#section-3.4)
es256jwsig = "DtEhU3ljbEg8L38VWAfUAqOyKAM6-Xx-F4GawxaepmXFCgfTjDxw" +
"5djxLa8ISlSApmWQxfKTUJqPP3-Kg6NU1Q"
// printf '{"alg":"ES256","jwk":{"crv":"P-256","kty":"EC","x":<testKeyECPubY>,"y":<testKeyECPubY>,"nonce":"nonce"}' | \
// base64 | tr -d '=' | tr '/+' '_-'
es256phead = "eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjVsaEV1" +
"ZzV4SzR4QkRaMm5BYmF4THRhTGl2ODVieEo3ZVBkMWRrTzIzSFEiLCJ5IjoiNGFpSzcyc0JlVUFH" +
"a3YwVGFMc213b2tZVVl5TnhHc1M1RU1JS3dzTklLayJ9LCJub25jZSI6Im5vbmNlIn0"
// printf '{"alg":"ES256","jwk":{"crv":"P-256","kty":"EC","x":<testKeyECPubY>,"y":<testKeyECPubY>},"nonce":"nonce","url":"url"}' | b64raw
es256phead = "eyJhbGciOiJFUzI1NiIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0" +
"eSI6IkVDIiwieCI6IjVsaEV1ZzV4SzR4QkRaMm5BYmF4THRhTGl2" +
"ODVieEo3ZVBkMWRrTzIzSFEiLCJ5IjoiNGFpSzcyc0JlVUFHa3Yw" +
"VGFMc213b2tZVVl5TnhHc1M1RU1JS3dzTklLayJ9LCJub25jZSI6" +
"Im5vbmNlIiwidXJsIjoidXJsIn0"
// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce","url":"url"}
// {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"}
rs256phead = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
"IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
"SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
@@ -349,30 +278,24 @@ func TestJWSEncodeJSONCustom(t *testing.T) {
"bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
"ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
"b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
"UVEifSwibm9uY2UiOiJub25jZSIsInVybCI6InVybCJ9"
"UVEifSwibm9uY2UiOiJub25jZSJ9"
)
tt := []struct {
alg, phead string
pub crypto.PublicKey
stdsig, jwsig string
alg, phead string
pub crypto.PublicKey
}{
{"ES256", es256phead, testKeyEC.Public(), es256stdsig, es256jwsig},
{"RS256", rs256phead, testKey.Public(), testsig, testsig},
{"RS256", rs256phead, testKey.Public()},
{"ES256", es256phead, testKeyEC.Public()},
}
for _, tc := range tt {
tc := tc
t.Run(tc.alg, func(t *testing.T) {
stdsig, err := base64.RawStdEncoding.DecodeString(tc.stdsig)
if err != nil {
t.Errorf("couldn't decode test vector: %v", err)
}
signer := &customTestSigner{
sig: stdsig,
sig: []byte("testsig"),
pub: tc.pub,
}
b, err := jwsEncodeJSON(claims, signer, noKeyID, "nonce", "url")
b, err := jwsEncodeJSON(claims, signer, "nonce")
if err != nil {
t.Fatal(err)
}
@@ -386,8 +309,8 @@ func TestJWSEncodeJSONCustom(t *testing.T) {
if j.Payload != payload {
t.Errorf("j.Payload = %q\nwant %q", j.Payload, payload)
}
if j.Signature != tc.jwsig {
t.Errorf("j.Signature = %q\nwant %q", j.Signature, tc.jwsig)
if j.Signature != testsig {
t.Errorf("j.Signature = %q\nwant %q", j.Signature, testsig)
}
})
}
@@ -429,8 +352,10 @@ func TestJWKThumbprintRSA(t *testing.T) {
func TestJWKThumbprintEC(t *testing.T) {
// Key example from RFC 7520
// expected was computed with
// printf '{"crv":"P-521","kty":"EC","x":"<base64X>","y":"<base64Y>"}' | \
// openssl dgst -binary -sha256 | b64raw
// echo -n '{"crv":"P-521","kty":"EC","x":"<base64X>","y":"<base64Y>"}' | \
// openssl dgst -binary -sha256 | \
// base64 | \
// tr -d '=' | tr '/+' '_-'
const (
base64X = "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkT" +
"KqjqvjyekWF-7ytDyRXYgCF5cj0Kt"
-392
View File
@@ -1,392 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package acme
import (
"context"
"crypto"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
)
// DeactivateReg permanently disables an existing account associated with c.Key.
// A deactivated account can no longer request certificate issuance or access
// resources related to the account, such as orders or authorizations.
//
// It only works with CAs implementing RFC 8555.
func (c *Client) DeactivateReg(ctx context.Context) error {
url := string(c.accountKID(ctx))
if url == "" {
return ErrNoAccount
}
req := json.RawMessage(`{"status": "deactivated"}`)
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
if err != nil {
return err
}
res.Body.Close()
return nil
}
// registerRFC is quivalent to c.Register but for CAs implementing RFC 8555.
// It expects c.Discover to have already been called.
// TODO: Implement externalAccountBinding.
func (c *Client) registerRFC(ctx context.Context, acct *Account, prompt func(tosURL string) bool) (*Account, error) {
c.cacheMu.Lock() // guard c.kid access
defer c.cacheMu.Unlock()
req := struct {
TermsAgreed bool `json:"termsOfServiceAgreed,omitempty"`
Contact []string `json:"contact,omitempty"`
}{
Contact: acct.Contact,
}
if c.dir.Terms != "" {
req.TermsAgreed = prompt(c.dir.Terms)
}
res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(
http.StatusOK, // account with this key already registered
http.StatusCreated, // new account created
))
if err != nil {
return nil, err
}
defer res.Body.Close()
a, err := responseAccount(res)
if err != nil {
return nil, err
}
// Cache Account URL even if we return an error to the caller.
// It is by all means a valid and usable "kid" value for future requests.
c.kid = keyID(a.URI)
if res.StatusCode == http.StatusOK {
return nil, ErrAccountAlreadyExists
}
return a, nil
}
// updateGegRFC is equivalent to c.UpdateReg but for CAs implementing RFC 8555.
// It expects c.Discover to have already been called.
func (c *Client) updateRegRFC(ctx context.Context, a *Account) (*Account, error) {
url := string(c.accountKID(ctx))
if url == "" {
return nil, ErrNoAccount
}
req := struct {
Contact []string `json:"contact,omitempty"`
}{
Contact: a.Contact,
}
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
return responseAccount(res)
}
// getGegRFC is equivalent to c.GetReg but for CAs implementing RFC 8555.
// It expects c.Discover to have already been called.
func (c *Client) getRegRFC(ctx context.Context) (*Account, error) {
req := json.RawMessage(`{"onlyReturnExisting": true}`)
res, err := c.post(ctx, c.Key, c.dir.RegURL, req, wantStatus(http.StatusOK))
if e, ok := err.(*Error); ok && e.ProblemType == "urn:ietf:params:acme:error:accountDoesNotExist" {
return nil, ErrNoAccount
}
if err != nil {
return nil, err
}
defer res.Body.Close()
return responseAccount(res)
}
func responseAccount(res *http.Response) (*Account, error) {
var v struct {
Status string
Contact []string
Orders string
}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: invalid account response: %v", err)
}
return &Account{
URI: res.Header.Get("Location"),
Status: v.Status,
Contact: v.Contact,
OrdersURL: v.Orders,
}, nil
}
// AuthorizeOrder initiates the order-based application for certificate issuance,
// as opposed to pre-authorization in Authorize.
// It is only supported by CAs implementing RFC 8555.
//
// The caller then needs to fetch each authorization with GetAuthorization,
// identify those with StatusPending status and fulfill a challenge using Accept.
// Once all authorizations are satisfied, the caller will typically want to poll
// order status using WaitOrder until it's in StatusReady state.
// To finalize the order and obtain a certificate, the caller submits a CSR with CreateOrderCert.
func (c *Client) AuthorizeOrder(ctx context.Context, id []AuthzID, opt ...OrderOption) (*Order, error) {
dir, err := c.Discover(ctx)
if err != nil {
return nil, err
}
req := struct {
Identifiers []wireAuthzID `json:"identifiers"`
NotBefore string `json:"notBefore,omitempty"`
NotAfter string `json:"notAfter,omitempty"`
}{}
for _, v := range id {
req.Identifiers = append(req.Identifiers, wireAuthzID{
Type: v.Type,
Value: v.Value,
})
}
for _, o := range opt {
switch o := o.(type) {
case orderNotBeforeOpt:
req.NotBefore = time.Time(o).Format(time.RFC3339)
case orderNotAfterOpt:
req.NotAfter = time.Time(o).Format(time.RFC3339)
default:
// Package's fault if we let this happen.
panic(fmt.Sprintf("unsupported order option type %T", o))
}
}
res, err := c.post(ctx, nil, dir.OrderURL, req, wantStatus(http.StatusCreated))
if err != nil {
return nil, err
}
defer res.Body.Close()
return responseOrder(res)
}
// GetOrder retrives an order identified by the given URL.
// For orders created with AuthorizeOrder, the url value is Order.URI.
//
// If a caller needs to poll an order until its status is final,
// see the WaitOrder method.
func (c *Client) GetOrder(ctx context.Context, url string) (*Order, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
return responseOrder(res)
}
// WaitOrder polls an order from the given URL until it is in one of the final states,
// StatusReady, StatusValid or StatusInvalid, the CA responded with a non-retryable error
// or the context is done.
//
// It returns a non-nil Order only if its Status is StatusReady or StatusValid.
// In all other cases WaitOrder returns an error.
// If the Status is StatusInvalid, the returned error is of type *OrderError.
func (c *Client) WaitOrder(ctx context.Context, url string) (*Order, error) {
if _, err := c.Discover(ctx); err != nil {
return nil, err
}
for {
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
o, err := responseOrder(res)
res.Body.Close()
switch {
case err != nil:
// Skip and retry.
case o.Status == StatusInvalid:
return nil, &OrderError{OrderURL: o.URI, Status: o.Status}
case o.Status == StatusReady || o.Status == StatusValid:
return o, nil
}
d := retryAfter(res.Header.Get("Retry-After"))
if d == 0 {
// Default retry-after.
// Same reasoning as in WaitAuthorization.
d = time.Second
}
t := time.NewTimer(d)
select {
case <-ctx.Done():
t.Stop()
return nil, ctx.Err()
case <-t.C:
// Retry.
}
}
}
func responseOrder(res *http.Response) (*Order, error) {
var v struct {
Status string
Expires time.Time
Identifiers []wireAuthzID
NotBefore time.Time
NotAfter time.Time
Error *wireError
Authorizations []string
Finalize string
Certificate string
}
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
return nil, fmt.Errorf("acme: error reading order: %v", err)
}
o := &Order{
URI: res.Header.Get("Location"),
Status: v.Status,
Expires: v.Expires,
NotBefore: v.NotBefore,
NotAfter: v.NotAfter,
AuthzURLs: v.Authorizations,
FinalizeURL: v.Finalize,
CertURL: v.Certificate,
}
for _, id := range v.Identifiers {
o.Identifiers = append(o.Identifiers, AuthzID{Type: id.Type, Value: id.Value})
}
if v.Error != nil {
o.Error = v.Error.error(nil /* headers */)
}
return o, nil
}
// CreateOrderCert submits the CSR (Certificate Signing Request) to a CA at the specified URL.
// The URL is the FinalizeURL field of an Order created with AuthorizeOrder.
//
// If the bundle argument is true, the returned value also contain the CA (issuer)
// certificate chain. Otherwise, only a leaf certificate is returned.
// The returned URL can be used to re-fetch the certificate using FetchCert.
//
// This method is only supported by CAs implementing RFC 8555. See CreateCert for pre-RFC CAs.
//
// CreateOrderCert returns an error if the CA's response is unreasonably large.
// Callers are encouraged to parse the returned value to ensure the certificate is valid and has the expected features.
func (c *Client) CreateOrderCert(ctx context.Context, url string, csr []byte, bundle bool) (der [][]byte, certURL string, err error) {
if _, err := c.Discover(ctx); err != nil { // required by c.accountKID
return nil, "", err
}
// RFC describes this as "finalize order" request.
req := struct {
CSR string `json:"csr"`
}{
CSR: base64.RawURLEncoding.EncodeToString(csr),
}
res, err := c.post(ctx, nil, url, req, wantStatus(http.StatusOK))
if err != nil {
return nil, "", err
}
defer res.Body.Close()
o, err := responseOrder(res)
if err != nil {
return nil, "", err
}
// Wait for CA to issue the cert if they haven't.
if o.Status != StatusValid {
o, err = c.WaitOrder(ctx, o.URI)
}
if err != nil {
return nil, "", err
}
// The only acceptable status post finalize and WaitOrder is "valid".
if o.Status != StatusValid {
return nil, "", &OrderError{OrderURL: o.URI, Status: o.Status}
}
crt, err := c.fetchCertRFC(ctx, o.CertURL, bundle)
return crt, o.CertURL, err
}
// fetchCertRFC downloads issued certificate from the given URL.
// It expects the CA to respond with PEM-encoded certificate chain.
//
// The URL argument is the CertURL field of Order.
func (c *Client) fetchCertRFC(ctx context.Context, url string, bundle bool) ([][]byte, error) {
res, err := c.postAsGet(ctx, url, wantStatus(http.StatusOK))
if err != nil {
return nil, err
}
defer res.Body.Close()
// Get all the bytes up to a sane maximum.
// Account very roughly for base64 overhead.
const max = maxCertChainSize + maxCertChainSize/33
b, err := ioutil.ReadAll(io.LimitReader(res.Body, max+1))
if err != nil {
return nil, fmt.Errorf("acme: fetch cert response stream: %v", err)
}
if len(b) > max {
return nil, errors.New("acme: certificate chain is too big")
}
// Decode PEM chain.
var chain [][]byte
for {
var p *pem.Block
p, b = pem.Decode(b)
if p == nil {
break
}
if p.Type != "CERTIFICATE" {
return nil, fmt.Errorf("acme: invalid PEM cert type %q", p.Type)
}
chain = append(chain, p.Bytes)
if !bundle {
return chain, nil
}
if len(chain) > maxChainLen {
return nil, errors.New("acme: certificate chain is too long")
}
}
if len(chain) == 0 {
return nil, errors.New("acme: certificate chain is empty")
}
return chain, nil
}
// sends a cert revocation request in either JWK form when key is non-nil or KID form otherwise.
func (c *Client) revokeCertRFC(ctx context.Context, key crypto.Signer, cert []byte, reason CRLReasonCode) error {
req := &struct {
Cert string `json:"certificate"`
Reason int `json:"reason"`
}{
Cert: base64.RawURLEncoding.EncodeToString(cert),
Reason: int(reason),
}
res, err := c.post(ctx, key, c.dir.RevokeURL, req, wantStatus(http.StatusOK))
if err != nil {
if isAlreadyRevoked(err) {
// Assume it is not an error to revoke an already revoked cert.
return nil
}
return err
}
defer res.Body.Close()
return nil
}
func isAlreadyRevoked(err error) bool {
e, ok := err.(*Error)
return ok && e.ProblemType == "urn:ietf:params:acme:error:alreadyRevoked"
}
-743
View File
@@ -1,743 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package acme
import (
"bytes"
"context"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
"encoding/json"
"encoding/pem"
"fmt"
"io/ioutil"
"math/big"
"net/http"
"net/http/httptest"
"reflect"
"sync"
"testing"
"time"
)
// While contents of this file is pertinent only to RFC8555,
// it is complementary to the tests in the other _test.go files
// many of which are valid for both pre- and RFC8555.
// This will make it easier to clean up the tests once non-RFC compliant
// code is removed.
func TestRFC_Discover(t *testing.T) {
const (
nonce = "https://example.com/acme/new-nonce"
reg = "https://example.com/acme/new-acct"
order = "https://example.com/acme/new-order"
authz = "https://example.com/acme/new-authz"
revoke = "https://example.com/acme/revoke-cert"
keychange = "https://example.com/acme/key-change"
metaTerms = "https://example.com/acme/terms/2017-5-30"
metaWebsite = "https://www.example.com/"
metaCAA = "example.com"
)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{
"newNonce": %q,
"newAccount": %q,
"newOrder": %q,
"newAuthz": %q,
"revokeCert": %q,
"keyChange": %q,
"meta": {
"termsOfService": %q,
"website": %q,
"caaIdentities": [%q],
"externalAccountRequired": true
}
}`, nonce, reg, order, authz, revoke, keychange, metaTerms, metaWebsite, metaCAA)
}))
defer ts.Close()
c := Client{DirectoryURL: ts.URL}
dir, err := c.Discover(context.Background())
if err != nil {
t.Fatal(err)
}
if dir.NonceURL != nonce {
t.Errorf("dir.NonceURL = %q; want %q", dir.NonceURL, nonce)
}
if dir.RegURL != reg {
t.Errorf("dir.RegURL = %q; want %q", dir.RegURL, reg)
}
if dir.OrderURL != order {
t.Errorf("dir.OrderURL = %q; want %q", dir.OrderURL, order)
}
if dir.AuthzURL != authz {
t.Errorf("dir.AuthzURL = %q; want %q", dir.AuthzURL, authz)
}
if dir.RevokeURL != revoke {
t.Errorf("dir.RevokeURL = %q; want %q", dir.RevokeURL, revoke)
}
if dir.KeyChangeURL != keychange {
t.Errorf("dir.KeyChangeURL = %q; want %q", dir.KeyChangeURL, keychange)
}
if dir.Terms != metaTerms {
t.Errorf("dir.Terms = %q; want %q", dir.Terms, metaTerms)
}
if dir.Website != metaWebsite {
t.Errorf("dir.Website = %q; want %q", dir.Website, metaWebsite)
}
if len(dir.CAA) == 0 || dir.CAA[0] != metaCAA {
t.Errorf("dir.CAA = %q; want [%q]", dir.CAA, metaCAA)
}
if !dir.ExternalAccountRequired {
t.Error("dir.Meta.ExternalAccountRequired is false")
}
}
func TestRFC_popNonce(t *testing.T) {
var count int
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// The Client uses only Directory.NonceURL when specified.
// Expect no other URL paths.
if r.URL.Path != "/new-nonce" {
t.Errorf("r.URL.Path = %q; want /new-nonce", r.URL.Path)
}
if count > 0 {
w.WriteHeader(http.StatusTooManyRequests)
return
}
count++
w.Header().Set("Replay-Nonce", "second")
}))
cl := &Client{
DirectoryURL: ts.URL,
dir: &Directory{NonceURL: ts.URL + "/new-nonce"},
}
cl.addNonce(http.Header{"Replay-Nonce": {"first"}})
for i, nonce := range []string{"first", "second"} {
v, err := cl.popNonce(context.Background(), "")
if err != nil {
t.Errorf("%d: cl.popNonce: %v", i, err)
}
if v != nonce {
t.Errorf("%d: cl.popNonce = %q; want %q", i, v, nonce)
}
}
// No more nonces and server replies with an error past first nonce fetch.
// Expected to fail.
if _, err := cl.popNonce(context.Background(), ""); err == nil {
t.Error("last cl.popNonce returned nil error")
}
}
func TestRFC_postKID(t *testing.T) {
var ts *httptest.Server
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/new-nonce":
w.Header().Set("Replay-Nonce", "nonce")
case "/new-account":
w.Header().Set("Location", "/account-1")
w.Write([]byte(`{"status":"valid"}`))
case "/post":
b, _ := ioutil.ReadAll(r.Body) // check err later in decodeJWSxxx
head, err := decodeJWSHead(bytes.NewReader(b))
if err != nil {
t.Errorf("decodeJWSHead: %v", err)
return
}
if head.KID != "/account-1" {
t.Errorf("head.KID = %q; want /account-1", head.KID)
}
if len(head.JWK) != 0 {
t.Errorf("head.JWK = %q; want zero map", head.JWK)
}
if v := ts.URL + "/post"; head.URL != v {
t.Errorf("head.URL = %q; want %q", head.URL, v)
}
var payload struct{ Msg string }
decodeJWSRequest(t, &payload, bytes.NewReader(b))
if payload.Msg != "ping" {
t.Errorf("payload.Msg = %q; want ping", payload.Msg)
}
w.Write([]byte("pong"))
default:
t.Errorf("unhandled %s %s", r.Method, r.URL)
w.WriteHeader(http.StatusBadRequest)
}
}))
defer ts.Close()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cl := &Client{
Key: testKey,
DirectoryURL: ts.URL,
dir: &Directory{
NonceURL: ts.URL + "/new-nonce",
RegURL: ts.URL + "/new-account",
OrderURL: "/force-rfc-mode",
},
}
req := json.RawMessage(`{"msg":"ping"}`)
res, err := cl.post(ctx, nil /* use kid */, ts.URL+"/post", req, wantStatus(http.StatusOK))
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
b, _ := ioutil.ReadAll(res.Body) // don't care about err - just checking b
if string(b) != "pong" {
t.Errorf("res.Body = %q; want pong", b)
}
}
// acmeServer simulates a subset of RFC8555 compliant CA.
//
// TODO: We also have x/crypto/acme/autocert/acmetest and startACMEServerStub in autocert_test.go.
// It feels like this acmeServer is a sweet spot between usefulness and added complexity.
// Also, acmetest and startACMEServerStub were both written for draft-02, no RFC support.
// The goal is to consolidate all into one ACME test server.
type acmeServer struct {
ts *httptest.Server
handler map[string]http.HandlerFunc // keyed by r.URL.Path
mu sync.Mutex
nnonce int
}
func newACMEServer() *acmeServer {
return &acmeServer{handler: make(map[string]http.HandlerFunc)}
}
func (s *acmeServer) handle(path string, f func(http.ResponseWriter, *http.Request)) {
s.handler[path] = http.HandlerFunc(f)
}
func (s *acmeServer) start() {
s.ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// Directory request.
if r.URL.Path == "/" {
fmt.Fprintf(w, `{
"newNonce": %q,
"newAccount": %q,
"newOrder": %q,
"newAuthz": %q,
"revokeCert": %q,
"meta": {"termsOfService": %q}
}`,
s.url("/acme/new-nonce"),
s.url("/acme/new-account"),
s.url("/acme/new-order"),
s.url("/acme/new-authz"),
s.url("/acme/revoke-cert"),
s.url("/terms"),
)
return
}
// All other responses contain a nonce value unconditionally.
w.Header().Set("Replay-Nonce", s.nonce())
if r.URL.Path == "/acme/new-nonce" {
return
}
h := s.handler[r.URL.Path]
if h == nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "Unhandled %s", r.URL.Path)
return
}
h.ServeHTTP(w, r)
}))
}
func (s *acmeServer) close() {
s.ts.Close()
}
func (s *acmeServer) url(path string) string {
return s.ts.URL + path
}
func (s *acmeServer) nonce() string {
s.mu.Lock()
defer s.mu.Unlock()
s.nnonce++
return fmt.Sprintf("nonce%d", s.nnonce)
}
func (s *acmeServer) error(w http.ResponseWriter, e *wireError) {
w.WriteHeader(e.Status)
json.NewEncoder(w).Encode(e)
}
func TestRFC_Register(t *testing.T) {
const email = "mailto:user@example.org"
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusCreated) // 201 means new account created
fmt.Fprintf(w, `{
"status": "valid",
"contact": [%q],
"orders": %q
}`, email, s.url("/accounts/1/orders"))
b, _ := ioutil.ReadAll(r.Body) // check err later in decodeJWSxxx
head, err := decodeJWSHead(bytes.NewReader(b))
if err != nil {
t.Errorf("decodeJWSHead: %v", err)
return
}
if len(head.JWK) == 0 {
t.Error("head.JWK is empty")
}
var req struct{ Contact []string }
decodeJWSRequest(t, &req, bytes.NewReader(b))
if len(req.Contact) != 1 || req.Contact[0] != email {
t.Errorf("req.Contact = %q; want [%q]", req.Contact, email)
}
})
s.start()
defer s.close()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cl := &Client{
Key: testKeyEC,
DirectoryURL: s.url("/"),
}
var didPrompt bool
a := &Account{Contact: []string{email}}
acct, err := cl.Register(ctx, a, func(tos string) bool {
didPrompt = true
terms := s.url("/terms")
if tos != terms {
t.Errorf("tos = %q; want %q", tos, terms)
}
return true
})
if err != nil {
t.Fatal(err)
}
okAccount := &Account{
URI: s.url("/accounts/1"),
Status: StatusValid,
Contact: []string{email},
OrdersURL: s.url("/accounts/1/orders"),
}
if !reflect.DeepEqual(acct, okAccount) {
t.Errorf("acct = %+v; want %+v", acct, okAccount)
}
if !didPrompt {
t.Error("tos prompt wasn't called")
}
if v := cl.accountKID(ctx); v != keyID(okAccount.URI) {
t.Errorf("account kid = %q; want %q", v, okAccount.URI)
}
}
func TestRFC_RegisterExisting(t *testing.T) {
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusOK) // 200 means account already exists
w.Write([]byte(`{"status": "valid"}`))
})
s.start()
defer s.close()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
_, err := cl.Register(context.Background(), &Account{}, AcceptTOS)
if err != ErrAccountAlreadyExists {
t.Errorf("err = %v; want %v", err, ErrAccountAlreadyExists)
}
kid := keyID(s.url("/accounts/1"))
if v := cl.accountKID(context.Background()); v != kid {
t.Errorf("account kid = %q; want %q", v, kid)
}
}
func TestRFC_UpdateReg(t *testing.T) {
const email = "mailto:user@example.org"
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "valid"}`))
})
var didUpdate bool
s.handle("/accounts/1", func(w http.ResponseWriter, r *http.Request) {
didUpdate = true
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "valid"}`))
b, _ := ioutil.ReadAll(r.Body) // check err later in decodeJWSxxx
head, err := decodeJWSHead(bytes.NewReader(b))
if err != nil {
t.Errorf("decodeJWSHead: %v", err)
return
}
if len(head.JWK) != 0 {
t.Error("head.JWK is non-zero")
}
kid := s.url("/accounts/1")
if head.KID != kid {
t.Errorf("head.KID = %q; want %q", head.KID, kid)
}
var req struct{ Contact []string }
decodeJWSRequest(t, &req, bytes.NewReader(b))
if len(req.Contact) != 1 || req.Contact[0] != email {
t.Errorf("req.Contact = %q; want [%q]", req.Contact, email)
}
})
s.start()
defer s.close()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
_, err := cl.UpdateReg(context.Background(), &Account{Contact: []string{email}})
if err != nil {
t.Error(err)
}
if !didUpdate {
t.Error("UpdateReg didn't update the account")
}
}
func TestRFC_GetReg(t *testing.T) {
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "valid"}`))
head, err := decodeJWSHead(r.Body)
if err != nil {
t.Errorf("decodeJWSHead: %v", err)
return
}
if len(head.JWK) == 0 {
t.Error("head.JWK is empty")
}
})
s.start()
defer s.close()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
acct, err := cl.GetReg(context.Background(), "")
if err != nil {
t.Fatal(err)
}
okAccount := &Account{
URI: s.url("/accounts/1"),
Status: StatusValid,
}
if !reflect.DeepEqual(acct, okAccount) {
t.Errorf("acct = %+v; want %+v", acct, okAccount)
}
}
func TestRFC_GetRegNoAccount(t *testing.T) {
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
s.error(w, &wireError{
Status: http.StatusBadRequest,
Type: "urn:ietf:params:acme:error:accountDoesNotExist",
})
})
s.start()
defer s.close()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
if _, err := cl.GetReg(context.Background(), ""); err != ErrNoAccount {
t.Errorf("err = %v; want %v", err, ErrNoAccount)
}
}
func TestRFC_GetRegOtherError(t *testing.T) {
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
})
s.start()
defer s.close()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
if _, err := cl.GetReg(context.Background(), ""); err == nil || err == ErrNoAccount {
t.Errorf("GetReg: %v; want any other non-nil err", err)
}
}
func TestRFC_AuthorizeOrder(t *testing.T) {
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "valid"}`))
})
s.handle("/acme/new-order", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/orders/1"))
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, `{
"status": "pending",
"expires": "2019-09-01T00:00:00Z",
"notBefore": "2019-08-31T00:00:00Z",
"notAfter": "2019-09-02T00:00:00Z",
"identifiers": [{"type":"dns", "value":"example.org"}],
"authorizations": [%q]
}`, s.url("/authz/1"))
})
s.start()
defer s.close()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
o, err := cl.AuthorizeOrder(context.Background(), DomainIDs("example.org"),
WithOrderNotBefore(time.Date(2019, 8, 31, 0, 0, 0, 0, time.UTC)),
WithOrderNotAfter(time.Date(2019, 9, 2, 0, 0, 0, 0, time.UTC)),
)
if err != nil {
t.Fatal(err)
}
okOrder := &Order{
URI: s.url("/orders/1"),
Status: StatusPending,
Expires: time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC),
NotBefore: time.Date(2019, 8, 31, 0, 0, 0, 0, time.UTC),
NotAfter: time.Date(2019, 9, 2, 0, 0, 0, 0, time.UTC),
Identifiers: []AuthzID{AuthzID{Type: "dns", Value: "example.org"}},
AuthzURLs: []string{s.url("/authz/1")},
}
if !reflect.DeepEqual(o, okOrder) {
t.Errorf("AuthorizeOrder = %+v; want %+v", o, okOrder)
}
}
func TestRFC_GetOrder(t *testing.T) {
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "valid"}`))
})
s.handle("/orders/1", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/orders/1"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{
"status": "invalid",
"expires": "2019-09-01T00:00:00Z",
"notBefore": "2019-08-31T00:00:00Z",
"notAfter": "2019-09-02T00:00:00Z",
"identifiers": [{"type":"dns", "value":"example.org"}],
"authorizations": ["/authz/1"],
"finalize": "/orders/1/fin",
"certificate": "/orders/1/cert",
"error": {"type": "badRequest"}
}`))
})
s.start()
defer s.close()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
o, err := cl.GetOrder(context.Background(), s.url("/orders/1"))
if err != nil {
t.Fatal(err)
}
okOrder := &Order{
URI: s.url("/orders/1"),
Status: StatusInvalid,
Expires: time.Date(2019, 9, 1, 0, 0, 0, 0, time.UTC),
NotBefore: time.Date(2019, 8, 31, 0, 0, 0, 0, time.UTC),
NotAfter: time.Date(2019, 9, 2, 0, 0, 0, 0, time.UTC),
Identifiers: []AuthzID{AuthzID{Type: "dns", Value: "example.org"}},
AuthzURLs: []string{"/authz/1"},
FinalizeURL: "/orders/1/fin",
CertURL: "/orders/1/cert",
Error: &Error{ProblemType: "badRequest"},
}
if !reflect.DeepEqual(o, okOrder) {
t.Errorf("GetOrder = %+v\nwant %+v", o, okOrder)
}
}
func TestRFC_WaitOrder(t *testing.T) {
for _, st := range []string{StatusReady, StatusValid} {
t.Run(st, func(t *testing.T) {
testWaitOrderStatus(t, st)
})
}
}
func testWaitOrderStatus(t *testing.T, okStatus string) {
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "valid"}`))
})
var count int
s.handle("/orders/1", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/orders/1"))
w.WriteHeader(http.StatusOK)
s := StatusPending
if count > 0 {
s = okStatus
}
fmt.Fprintf(w, `{"status": %q}`, s)
count++
})
s.start()
defer s.close()
var order *Order
var err error
done := make(chan struct{})
go func() {
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
order, err = cl.WaitOrder(context.Background(), s.url("/orders/1"))
close(done)
}()
select {
case <-time.After(3 * time.Second):
t.Fatal("WaitOrder took too long to return")
case <-done:
if err != nil {
t.Fatalf("WaitOrder: %v", err)
}
if order.Status != okStatus {
t.Errorf("order.Status = %q; want %q", order.Status, okStatus)
}
}
}
func TestRFC_WaitOrderError(t *testing.T) {
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "valid"}`))
})
var count int
s.handle("/orders/1", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/orders/1"))
w.WriteHeader(http.StatusOK)
s := StatusPending
if count > 0 {
s = StatusInvalid
}
fmt.Fprintf(w, `{"status": %q}`, s)
count++
})
s.start()
defer s.close()
var err error
done := make(chan struct{})
go func() {
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
_, err = cl.WaitOrder(context.Background(), s.url("/orders/1"))
close(done)
}()
select {
case <-time.After(3 * time.Second):
t.Fatal("WaitOrder took too long to return")
case <-done:
if err == nil {
t.Fatal("WaitOrder returned nil error")
}
e, ok := err.(*OrderError)
if !ok {
t.Fatalf("err = %v (%T); want OrderError", err, err)
}
if e.OrderURL != s.url("/orders/1") {
t.Errorf("e.OrderURL = %q; want %q", e.OrderURL, s.url("/orders/1"))
}
if e.Status != StatusInvalid {
t.Errorf("e.Status = %q; want %q", e.Status, StatusInvalid)
}
}
}
func TestRFC_CreateOrderCert(t *testing.T) {
q := &x509.CertificateRequest{
Subject: pkix.Name{CommonName: "example.org"},
}
csr, err := x509.CreateCertificateRequest(rand.Reader, q, testKeyEC)
if err != nil {
t.Fatal(err)
}
tmpl := &x509.Certificate{SerialNumber: big.NewInt(1)}
leaf, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &testKeyEC.PublicKey, testKeyEC)
if err != nil {
t.Fatal(err)
}
s := newACMEServer()
s.handle("/acme/new-account", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/accounts/1"))
w.Write([]byte(`{"status": "valid"}`))
})
var count int
s.handle("/pleaseissue", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", s.url("/pleaseissue"))
st := StatusProcessing
if count > 0 {
st = StatusValid
}
fmt.Fprintf(w, `{"status":%q, "certificate":%q}`, st, s.url("/crt"))
count++
})
s.handle("/crt", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/pem-certificate-chain")
pem.Encode(w, &pem.Block{Type: "CERTIFICATE", Bytes: leaf})
})
s.start()
defer s.close()
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
cert, curl, err := cl.CreateOrderCert(ctx, s.url("/pleaseissue"), csr, true)
if err != nil {
t.Fatalf("CreateOrderCert: %v", err)
}
if _, err := x509.ParseCertificate(cert[0]); err != nil {
t.Errorf("ParseCertificate: %v", err)
}
if !reflect.DeepEqual(cert[0], leaf) {
t.Errorf("cert and leaf bytes don't match")
}
if u := s.url("/crt"); curl != u {
t.Errorf("curl = %q; want %q", curl, u)
}
}
func TestRFC_AlreadyRevokedCert(t *testing.T) {
s := newACMEServer()
s.handle("/acme/revoke-cert", func(w http.ResponseWriter, r *http.Request) {
s.error(w, &wireError{
Status: http.StatusBadRequest,
Type: "urn:ietf:params:acme:error:alreadyRevoked",
})
})
s.start()
defer s.close()
cl := &Client{Key: testKeyEC, DirectoryURL: s.url("/")}
err := cl.RevokeCert(context.Background(), testKeyEC, []byte{0}, CRLReasonUnspecified)
if err != nil {
t.Fatalf("RevokeCert: %v", err)
}
}
+45 -276
View File
@@ -14,18 +14,14 @@ import (
"time"
)
// ACME status values of Account, Order, Authorization and Challenge objects.
// See https://tools.ietf.org/html/rfc8555#section-7.1.6 for details.
// ACME server response statuses used to describe Authorization and Challenge states.
const (
StatusDeactivated = "deactivated"
StatusExpired = "expired"
StatusInvalid = "invalid"
StatusPending = "pending"
StatusProcessing = "processing"
StatusReady = "ready"
StatusRevoked = "revoked"
StatusUnknown = "unknown"
StatusValid = "valid"
StatusUnknown = "unknown"
StatusPending = "pending"
StatusProcessing = "processing"
StatusValid = "valid"
StatusInvalid = "invalid"
StatusRevoked = "revoked"
)
// CRLReasonCode identifies the reason for a certificate revocation.
@@ -45,17 +41,8 @@ const (
CRLReasonAACompromise CRLReasonCode = 10
)
var (
// ErrUnsupportedKey is returned when an unsupported key type is encountered.
ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
// ErrAccountAlreadyExists indicates that the Client's key has already been registered
// with the CA. It is returned by Register method.
ErrAccountAlreadyExists = errors.New("acme: account already exists")
// ErrNoAccount indicates that the Client's key has not been registered with the CA.
ErrNoAccount = errors.New("acme: account does not exist")
)
// ErrUnsupportedKey is returned when an unsupported key type is encountered.
var ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
// Error is an ACME error, defined in Problem Details for HTTP APIs doc
// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
@@ -67,12 +54,6 @@ type Error struct {
ProblemType string
// Detail is a human-readable explanation specific to this occurrence of the problem.
Detail string
// Instance indicates a URL that the client should direct a human user to visit
// in order for instructions on how to agree to the updated Terms of Service.
// In such an event CA sets StatusCode to 403, ProblemType to
// "urn:ietf:params:acme:error:userActionRequired" and a Link header with relation
// "terms-of-service" containing the latest TOS URL.
Instance string
// Header is the original server error response headers.
// It may be nil.
Header http.Header
@@ -102,27 +83,7 @@ func (a *AuthorizationError) Error() string {
for i, err := range a.Errors {
e[i] = err.Error()
}
if a.Identifier != "" {
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
}
return fmt.Sprintf("acme: authorization error: %s", strings.Join(e, "; "))
}
// OrderError is returned from Client's order related methods.
// It indicates the order is unusable and the clients should start over with
// AuthorizeOrder.
//
// The clients can still fetch the order object from CA using GetOrder
// to inspect its state.
type OrderError struct {
OrderURL string
Status string
}
func (oe *OrderError) Error() string {
return fmt.Sprintf("acme: order %s status: %s", oe.OrderURL, oe.Status)
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
}
// RateLimit reports whether err represents a rate limit error and
@@ -147,88 +108,49 @@ func RateLimit(err error) (time.Duration, bool) {
}
// Account is a user account. It is associated with a private key.
// Non-RFC 8555 fields are empty when interfacing with a compliant CA.
type Account struct {
// URI is the account unique ID, which is also a URL used to retrieve
// account data from the CA.
// When interfacing with RFC 8555-compliant CAs, URI is the "kid" field
// value in JWS signed requests.
URI string
// Contact is a slice of contact info used during registration.
// See https://tools.ietf.org/html/rfc8555#section-7.3 for supported
// formats.
Contact []string
// Status indicates current account status as returned by the CA.
// Possible values are StatusValid, StatusDeactivated, and StatusRevoked.
Status string
// OrdersURL is a URL from which a list of orders submitted by this account
// can be fetched.
OrdersURL string
// The terms user has agreed to.
// A value not matching CurrentTerms indicates that the user hasn't agreed
// to the actual Terms of Service of the CA.
//
// It is non-RFC 8555 compliant. Package users can store the ToS they agree to
// during Client's Register call in the prompt callback function.
AgreedTerms string
// Actual terms of a CA.
//
// It is non-RFC 8555 compliant. Use Directory's Terms field.
// When a CA updates their terms and requires an account agreement,
// a URL at which instructions to do so is available in Error's Instance field.
CurrentTerms string
// Authz is the authorization URL used to initiate a new authz flow.
//
// It is non-RFC 8555 compliant. Use Directory's AuthzURL or OrderURL.
Authz string
// Authorizations is a URI from which a list of authorizations
// granted to this account can be fetched via a GET request.
//
// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
Authorizations string
// Certificates is a URI from which a list of certificates
// issued for this account can be fetched via a GET request.
//
// It is non-RFC 8555 compliant and is obsoleted by OrdersURL.
Certificates string
}
// Directory is ACME server discovery data.
// See https://tools.ietf.org/html/rfc8555#section-7.1.1 for more details.
type Directory struct {
// NonceURL indicates an endpoint where to fetch fresh nonce values from.
NonceURL string
// RegURL is an account endpoint URL, allowing for creating new accounts.
// Pre-RFC 8555 CAs also allow modifying existing accounts at this URL.
// RegURL is an account endpoint URL, allowing for creating new
// and modifying existing accounts.
RegURL string
// OrderURL is used to initiate the certificate issuance flow
// as described in RFC 8555.
OrderURL string
// AuthzURL is used to initiate identifier pre-authorization flow.
// Empty string indicates the flow is unsupported by the CA.
// AuthzURL is used to initiate Identifier Authorization flow.
AuthzURL string
// CertURL is a new certificate issuance endpoint URL.
// It is non-RFC 8555 compliant and is obsoleted by OrderURL.
CertURL string
// RevokeURL is used to initiate a certificate revocation flow.
RevokeURL string
// KeyChangeURL allows to perform account key rollover flow.
KeyChangeURL string
// Term is a URI identifying the current terms of service.
Terms string
@@ -240,126 +162,44 @@ type Directory struct {
// recognises as referring to itself for the purposes of CAA record validation
// as defined in RFC6844.
CAA []string
// ExternalAccountRequired indicates that the CA requires for all account-related
// requests to include external account binding information.
ExternalAccountRequired bool
}
// rfcCompliant reports whether the ACME server implements RFC 8555.
// Note that some servers may have incomplete RFC implementation
// even if the returned value is true.
// If rfcCompliant reports false, the server most likely implements draft-02.
func (d *Directory) rfcCompliant() bool {
return d.OrderURL != ""
}
// Challenge encodes a returned CA challenge.
// Its Error field may be non-nil if the challenge is part of an Authorization
// with StatusInvalid.
type Challenge struct {
// Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
Type string
// Order represents a client's request for a certificate.
// It tracks the request flow progress through to issuance.
type Order struct {
// URI uniquely identifies an order.
// URI is where a challenge response can be posted to.
URI string
// Status represents the current status of the order.
// It indicates which action the client should take.
//
// Possible values are StatusPending, StatusReady, StatusProcessing, StatusValid and StatusInvalid.
// Pending means the CA does not believe that the client has fulfilled the requirements.
// Ready indicates that the client has fulfilled all the requirements and can submit a CSR
// to obtain a certificate. This is done with Client's CreateOrderCert.
// Processing means the certificate is being issued.
// Valid indicates the CA has issued the certificate. It can be downloaded
// from the Order's CertURL. This is done with Client's FetchCert.
// Invalid means the certificate will not be issued. Users should consider this order
// abandoned.
// Token is a random value that uniquely identifies the challenge.
Token string
// Status identifies the status of this challenge.
Status string
// Expires is the timestamp after which CA considers this order invalid.
Expires time.Time
// Identifiers contains all identifier objects which the order pertains to.
Identifiers []AuthzID
// NotBefore is the requested value of the notBefore field in the certificate.
NotBefore time.Time
// NotAfter is the requested value of the notAfter field in the certificate.
NotAfter time.Time
// AuthzURLs represents authorizations to complete before a certificate
// for identifiers specified in the order can be issued.
// It also contains unexpired authorizations that the client has completed
// in the past.
//
// Authorization objects can be fetched using Client's GetAuthorization method.
//
// The required authorizations are dictated by CA policies.
// There may not be a 1:1 relationship between the identifiers and required authorizations.
// Required authorizations can be identified by their StatusPending status.
//
// For orders in the StatusValid or StatusInvalid state these are the authorizations
// which were completed.
AuthzURLs []string
// FinalizeURL is the endpoint at which a CSR is submitted to obtain a certificate
// once all the authorizations are satisfied.
FinalizeURL string
// CertURL points to the certificate that has been issued in response to this order.
CertURL string
// The error that occurred while processing the order as received from a CA, if any.
Error *Error
// Error indicates the reason for an authorization failure
// when this challenge was used.
// The type of a non-nil value is *Error.
Error error
}
// OrderOption allows customizing Client.AuthorizeOrder call.
type OrderOption interface {
privateOrderOpt()
}
// WithOrderNotBefore sets order's NotBefore field.
func WithOrderNotBefore(t time.Time) OrderOption {
return orderNotBeforeOpt(t)
}
// WithOrderNotAfter sets order's NotAfter field.
func WithOrderNotAfter(t time.Time) OrderOption {
return orderNotAfterOpt(t)
}
type orderNotBeforeOpt time.Time
func (orderNotBeforeOpt) privateOrderOpt() {}
type orderNotAfterOpt time.Time
func (orderNotAfterOpt) privateOrderOpt() {}
// Authorization encodes an authorization response.
type Authorization struct {
// URI uniquely identifies a authorization.
URI string
// Status is the current status of an authorization.
// Possible values are StatusPending, StatusValid, StatusInvalid, StatusDeactivated,
// StatusExpired and StatusRevoked.
// Status identifies the status of an authorization.
Status string
// Identifier is what the account is authorized to represent.
Identifier AuthzID
// The timestamp after which the CA considers the authorization invalid.
Expires time.Time
// Wildcard is true for authorizations of a wildcard domain name.
Wildcard bool
// Challenges that the client needs to fulfill in order to prove possession
// of the identifier (for pending authorizations).
// For valid authorizations, the challenge that was validated.
// For invalid authorizations, the challenge that was attempted and failed.
//
// RFC 8555 compatible CAs require users to fuflfill only one of the challenges.
// For final authorizations, the challenges that were used.
Challenges []*Challenge
// A collection of sets of challenges, each of which would be sufficient
@@ -367,52 +207,24 @@ type Authorization struct {
// Clients must complete a set of challenges that covers at least one set.
// Challenges are identified by their indices in the challenges array.
// If this field is empty, the client needs to complete all challenges.
//
// This field is unused in RFC 8555.
Combinations [][]int
}
// AuthzID is an identifier that an account is authorized to represent.
type AuthzID struct {
Type string // The type of identifier, "dns" or "ip".
Type string // The type of identifier, e.g. "dns".
Value string // The identifier itself, e.g. "example.org".
}
// DomainIDs creates a slice of AuthzID with "dns" identifier type.
func DomainIDs(names ...string) []AuthzID {
a := make([]AuthzID, len(names))
for i, v := range names {
a[i] = AuthzID{Type: "dns", Value: v}
}
return a
}
// IPIDs creates a slice of AuthzID with "ip" identifier type.
// Each element of addr is textual form of an address as defined
// in RFC1123 Section 2.1 for IPv4 and in RFC5952 Section 4 for IPv6.
func IPIDs(addr ...string) []AuthzID {
a := make([]AuthzID, len(addr))
for i, v := range addr {
a[i] = AuthzID{Type: "ip", Value: v}
}
return a
}
// wireAuthzID is ACME JSON representation of authorization identifier objects.
type wireAuthzID struct {
Type string `json:"type"`
Value string `json:"value"`
}
// wireAuthz is ACME JSON representation of Authorization objects.
type wireAuthz struct {
Identifier wireAuthzID
Status string
Expires time.Time
Wildcard bool
Challenges []wireChallenge
Combinations [][]int
Error *wireError
Identifier struct {
Type string
Value string
}
}
func (z *wireAuthz) authorization(uri string) *Authorization {
@@ -420,10 +232,8 @@ func (z *wireAuthz) authorization(uri string) *Authorization {
URI: uri,
Status: z.Status,
Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
Expires: z.Expires,
Wildcard: z.Wildcard,
Challenges: make([]*Challenge, len(z.Challenges)),
Combinations: z.Combinations, // shallow copy
Challenges: make([]*Challenge, len(z.Challenges)),
}
for i, v := range z.Challenges {
a.Challenges[i] = v.challenge()
@@ -436,69 +246,30 @@ func (z *wireAuthz) error(uri string) *AuthorizationError {
URI: uri,
Identifier: z.Identifier.Value,
}
if z.Error != nil {
err.Errors = append(err.Errors, z.Error.error(nil))
}
for _, raw := range z.Challenges {
if raw.Error != nil {
err.Errors = append(err.Errors, raw.Error.error(nil))
}
}
return err
}
// Challenge encodes a returned CA challenge.
// Its Error field may be non-nil if the challenge is part of an Authorization
// with StatusInvalid.
type Challenge struct {
// Type is the challenge type, e.g. "http-01", "tls-alpn-01", "dns-01".
Type string
// URI is where a challenge response can be posted to.
URI string
// Token is a random value that uniquely identifies the challenge.
Token string
// Status identifies the status of this challenge.
// In RFC 8555, possible values are StatusPending, StatusProcessing, StatusValid,
// and StatusInvalid.
Status string
// Validated is the time at which the CA validated this challenge.
// Always zero value in pre-RFC 8555.
Validated time.Time
// Error indicates the reason for an authorization failure
// when this challenge was used.
// The type of a non-nil value is *Error.
Error error
}
// wireChallenge is ACME JSON challenge representation.
type wireChallenge struct {
URL string `json:"url"` // RFC
URI string `json:"uri"` // pre-RFC
Type string
Token string
Status string
Validated time.Time
Error *wireError
URI string `json:"uri"`
Type string
Token string
Status string
Error *wireError
}
func (c *wireChallenge) challenge() *Challenge {
v := &Challenge{
URI: c.URL,
URI: c.URI,
Type: c.Type,
Token: c.Token,
Status: c.Status,
}
if v.URI == "" {
v.URI = c.URI // c.URL was empty; use legacy
}
if v.Status == "" {
v.Status = StatusPending
}
@@ -511,10 +282,9 @@ func (c *wireChallenge) challenge() *Challenge {
// wireError is a subset of fields of the Problem Details object
// as described in https://tools.ietf.org/html/rfc7807#section-3.1.
type wireError struct {
Status int
Type string
Detail string
Instance string
Status int
Type string
Detail string
}
func (e *wireError) error(h http.Header) *Error {
@@ -522,7 +292,6 @@ func (e *wireError) error(h http.Header) *Error {
StatusCode: e.Status,
ProblemType: e.Type,
Detail: e.Detail,
Instance: e.Instance,
Header: h,
}
}
-43
View File
@@ -61,46 +61,3 @@ func TestRateLimit(t *testing.T) {
}
}
}
func TestAuthorizationError(t *testing.T) {
tests := []struct {
desc string
err *AuthorizationError
msg string
}{
{
desc: "when auth error identifier is set",
err: &AuthorizationError{
Identifier: "domain.com",
Errors: []error{
(&wireError{
Status: 403,
Type: "urn:ietf:params:acme:error:caa",
Detail: "CAA record for domain.com prevents issuance",
}).error(nil),
},
},
msg: "acme: authorization error for domain.com: 403 urn:ietf:params:acme:error:caa: CAA record for domain.com prevents issuance",
},
{
desc: "when auth error identifier is unset",
err: &AuthorizationError{
Errors: []error{
(&wireError{
Status: 403,
Type: "urn:ietf:params:acme:error:caa",
Detail: "CAA record for domain.com prevents issuance",
}).error(nil),
},
},
msg: "acme: authorization error: 403 urn:ietf:params:acme:error:caa: CAA record for domain.com prevents issuance",
},
}
for _, tt := range tests {
if tt.err.Error() != tt.msg {
t.Errorf("got: %s\nwant: %s", tt.err, tt.msg)
}
}
}
-27
View File
@@ -1,27 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.12
package acme
import "runtime/debug"
func init() {
// Set packageVersion if the binary was built in modules mode and x/crypto
// was not replaced with a different module.
info, ok := debug.ReadBuildInfo()
if !ok {
return
}
for _, m := range info.Deps {
if m.Path != "golang.org/x/crypto" {
continue
}
if m.Replace == nil {
packageVersion = m.Version
}
break
}
}
-2
View File
@@ -5,8 +5,6 @@
// Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693
// and the extendable output function (XOF) BLAKE2Xb.
//
// BLAKE2b is optimized for 64-bit platforms—including NEON-enabled ARMs—and
// produces digests of any size between 1 and 64 bytes.
// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf
// and for BLAKE2Xb see https://blake2.net/blake2x.pdf
//
-2
View File
@@ -5,8 +5,6 @@
// Package blake2s implements the BLAKE2s hash algorithm defined by RFC 7693
// and the extendable output function (XOF) BLAKE2Xs.
//
// BLAKE2s is optimized for 8- to 32-bit platforms and produces digests of any
// size between 1 and 32 bytes.
// For a detailed specification of BLAKE2s see https://blake2.net/blake2.pdf
// and for BLAKE2Xs see https://blake2.net/blake2x.pdf
//
-16
View File
@@ -1,16 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11,!gccgo,!purego
package chacha20
const bufSize = 256
//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
}
-398
View File
@@ -1,398 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms
// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01.
package chacha20
import (
"crypto/cipher"
"encoding/binary"
"errors"
"math/bits"
"golang.org/x/crypto/internal/subtle"
)
const (
// KeySize is the size of the key used by this cipher, in bytes.
KeySize = 32
// NonceSize is the size of the nonce used with the standard variant of this
// cipher, 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 variant of
// this cipher, in bytes.
NonceSizeX = 24
)
// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key
// and nonce. A *Cipher implements the cipher.Stream interface.
type Cipher struct {
// The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter
// (incremented after each block), and 3 of nonce.
key [8]uint32
counter uint32
nonce [3]uint32
// The last len bytes of buf are leftover key stream bytes from the previous
// XORKeyStream invocation. The size of buf depends on how many blocks are
// computed at a time by xorKeyStreamBlocks.
buf [bufSize]byte
len int
// overflow is set when the counter overflowed, no more blocks can be
// generated, and the next XORKeyStream call should panic.
overflow bool
// The counter-independent results of the first round are cached after they
// are computed the first time.
precompDone bool
p1, p5, p9, p13 uint32
p2, p6, p10, p14 uint32
p3, p7, p11, p15 uint32
}
var _ cipher.Stream = (*Cipher)(nil)
// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given
// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided,
// the XChaCha20 construction will be used. It returns an error if key or nonce
// have any other length.
//
// Note that ChaCha20, like all stream ciphers, is not authenticated and allows
// attackers to silently tamper with the plaintext. For this reason, it is more
// appropriate as a building block than as a standalone encryption mechanism.
// Instead, consider using package golang.org/x/crypto/chacha20poly1305.
func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) {
// This function is split into a wrapper so that the Cipher allocation will
// be inlined, and depending on how the caller uses the return value, won't
// escape to the heap.
c := &Cipher{}
return newUnauthenticatedCipher(c, key, nonce)
}
func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) {
if len(key) != KeySize {
return nil, errors.New("chacha20: wrong key size")
}
if len(nonce) == NonceSizeX {
// XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a
// derived key, allowing it to operate on a nonce of 24 bytes. See
// draft-irtf-cfrg-xchacha-01, Section 2.3.
key, _ = HChaCha20(key, nonce[0:16])
cNonce := make([]byte, NonceSize)
copy(cNonce[4:12], nonce[16:24])
nonce = cNonce
} else if len(nonce) != NonceSize {
return nil, errors.New("chacha20: wrong nonce size")
}
key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint
c.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]),
}
c.nonce = [3]uint32{
binary.LittleEndian.Uint32(nonce[0:4]),
binary.LittleEndian.Uint32(nonce[4:8]),
binary.LittleEndian.Uint32(nonce[8:12]),
}
return c, nil
}
// The constant first 4 words of the ChaCha20 state.
const (
j0 uint32 = 0x61707865 // expa
j1 uint32 = 0x3320646e // nd 3
j2 uint32 = 0x79622d32 // 2-by
j3 uint32 = 0x6b206574 // te k
)
const blockSize = 64
// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words.
// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16
// words each round, in columnar or diagonal groups of 4 at a time.
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
a += b
d ^= a
d = bits.RotateLeft32(d, 16)
c += d
b ^= c
b = bits.RotateLeft32(b, 12)
a += b
d ^= a
d = bits.RotateLeft32(d, 8)
c += d
b ^= c
b = bits.RotateLeft32(b, 7)
return a, b, c, d
}
// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
// behave as if (64 * counter) bytes had been encrypted so far.
//
// To prevent accidental counter reuse, SetCounter panics if counter is less
// than the current value.
//
// Note that the execution time of XORKeyStream is not independent of the
// counter value.
func (s *Cipher) SetCounter(counter uint32) {
// Internally, s may buffer multiple blocks, which complicates this
// implementation slightly. When checking whether the counter has rolled
// back, we must use both s.counter and s.len to determine how many blocks
// we have already output.
outputCounter := s.counter - uint32(s.len)/blockSize
if s.overflow || counter < outputCounter {
panic("chacha20: SetCounter attempted to rollback counter")
}
// In the general case, we set the new counter value and reset s.len to 0,
// causing the next call to XORKeyStream to refill the buffer. However, if
// we're advancing within the existing buffer, we can save work by simply
// setting s.len.
if counter < s.counter {
s.len = int(s.counter-counter) * blockSize
} else {
s.counter = counter
s.len = 0
}
}
// 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(src) == 0 {
return
}
if len(dst) < len(src) {
panic("chacha20: output smaller than input")
}
dst = dst[:len(src)]
if subtle.InexactOverlap(dst, src) {
panic("chacha20: invalid buffer overlap")
}
// First, drain any remaining key stream from a previous XORKeyStream.
if s.len != 0 {
keyStream := s.buf[bufSize-s.len:]
if len(src) < len(keyStream) {
keyStream = keyStream[:len(src)]
}
_ = src[len(keyStream)-1] // bounds check elimination hint
for i, b := range keyStream {
dst[i] = src[i] ^ b
}
s.len -= len(keyStream)
dst, src = dst[len(keyStream):], src[len(keyStream):]
}
if len(src) == 0 {
return
}
// If we'd need to let the counter overflow and keep generating output,
// panic immediately. If instead we'd only reach the last block, remember
// not to generate any more output after the buffer is drained.
numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize
if s.overflow || uint64(s.counter)+numBlocks > 1<<32 {
panic("chacha20: counter overflow")
} else if uint64(s.counter)+numBlocks == 1<<32 {
s.overflow = true
}
// xorKeyStreamBlocks implementations expect input lengths that are a
// multiple of bufSize. Platform-specific ones process multiple blocks at a
// time, so have bufSizes that are a multiple of blockSize.
full := len(src) - len(src)%bufSize
if full > 0 {
s.xorKeyStreamBlocks(dst[:full], src[:full])
}
dst, src = dst[full:], src[full:]
// If using a multi-block xorKeyStreamBlocks would overflow, use the generic
// one that does one block at a time.
const blocksPerBuf = bufSize / blockSize
if uint64(s.counter)+blocksPerBuf > 1<<32 {
s.buf = [bufSize]byte{}
numBlocks := (len(src) + blockSize - 1) / blockSize
buf := s.buf[bufSize-numBlocks*blockSize:]
copy(buf, src)
s.xorKeyStreamBlocksGeneric(buf, buf)
s.len = len(buf) - copy(dst, buf)
return
}
// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
// keep the leftover keystream for the next XORKeyStream invocation.
if len(src) > 0 {
s.buf = [bufSize]byte{}
copy(s.buf[:], src)
s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
s.len = bufSize - copy(dst, s.buf[:])
}
}
func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
if len(dst) != len(src) || len(dst)%blockSize != 0 {
panic("chacha20: internal error: wrong dst and/or src length")
}
// To generate each block of key stream, the initial cipher state
// (represented below) is passed through 20 rounds of shuffling,
// alternatively applying quarterRounds by columns (like 1, 5, 9, 13)
// or by diagonals (like 1, 6, 11, 12).
//
// 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc
// 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk
// 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk
// 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn
//
// c=constant k=key b=blockcount n=nonce
var (
c0, c1, c2, c3 = j0, j1, j2, j3
c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3]
c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7]
_, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2]
)
// Three quarters of the first round don't depend on the counter, so we can
// calculate them here, and reuse them for multiple blocks in the loop, and
// for future XORKeyStream invocations.
if !s.precompDone {
s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13)
s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14)
s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15)
s.precompDone = true
}
// A condition of len(src) > 0 would be sufficient, but this also
// acts as a bounds check elimination hint.
for len(src) >= 64 && len(dst) >= 64 {
// The remainder of the first column round.
fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter)
// The second diagonal round.
x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15)
x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12)
x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13)
x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14)
// The remaining 18 rounds.
for i := 0; i < 9; i++ {
// Column round.
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)
// Diagonal round.
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)
}
// Add back the initial state to generate the key stream, then
// XOR the key stream with the source and write out the result.
addXor(dst[0:4], src[0:4], x0, c0)
addXor(dst[4:8], src[4:8], x1, c1)
addXor(dst[8:12], src[8:12], x2, c2)
addXor(dst[12:16], src[12:16], x3, c3)
addXor(dst[16:20], src[16:20], x4, c4)
addXor(dst[20:24], src[20:24], x5, c5)
addXor(dst[24:28], src[24:28], x6, c6)
addXor(dst[28:32], src[28:32], x7, c7)
addXor(dst[32:36], src[32:36], x8, c8)
addXor(dst[36:40], src[36:40], x9, c9)
addXor(dst[40:44], src[40:44], x10, c10)
addXor(dst[44:48], src[44:48], x11, c11)
addXor(dst[48:52], src[48:52], x12, s.counter)
addXor(dst[52:56], src[52:56], x13, c13)
addXor(dst[56:60], src[56:60], x14, c14)
addXor(dst[60:64], src[60:64], x15, c15)
s.counter += 1
src, dst = src[blockSize:], dst[blockSize:]
}
}
// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes
// key and a 16 bytes nonce. It returns an error if key or nonce have any other
// length. It is used as part of the XChaCha20 construction.
func HChaCha20(key, nonce []byte) ([]byte, error) {
// This function is split into a wrapper so that the slice allocation will
// be inlined, and depending on how the caller uses the return value, won't
// escape to the heap.
out := make([]byte, 32)
return hChaCha20(out, key, nonce)
}
func hChaCha20(out, key, nonce []byte) ([]byte, error) {
if len(key) != KeySize {
return nil, errors.New("chacha20: wrong HChaCha20 key size")
}
if len(nonce) != 16 {
return nil, errors.New("chacha20: wrong HChaCha20 nonce size")
}
x0, x1, x2, x3 := j0, j1, j2, j3
x4 := binary.LittleEndian.Uint32(key[0:4])
x5 := binary.LittleEndian.Uint32(key[4:8])
x6 := binary.LittleEndian.Uint32(key[8:12])
x7 := binary.LittleEndian.Uint32(key[12:16])
x8 := binary.LittleEndian.Uint32(key[16:20])
x9 := binary.LittleEndian.Uint32(key[20:24])
x10 := binary.LittleEndian.Uint32(key[24:28])
x11 := binary.LittleEndian.Uint32(key[28:32])
x12 := binary.LittleEndian.Uint32(nonce[0:4])
x13 := binary.LittleEndian.Uint32(nonce[4:8])
x14 := binary.LittleEndian.Uint32(nonce[8:12])
x15 := binary.LittleEndian.Uint32(nonce[12:16])
for i := 0; i < 10; i++ {
// Diagonal round.
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)
// Column round.
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)
}
_ = out[31] // bounds check elimination hint
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], x12)
binary.LittleEndian.PutUint32(out[20:24], x13)
binary.LittleEndian.PutUint32(out[24:28], x14)
binary.LittleEndian.PutUint32(out[28:32], x15)
return out, nil
}
-16
View File
@@ -1,16 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
package chacha20
const bufSize = 256
//go:noescape
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
}
-449
View File
@@ -1,449 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on CRYPTOGAMS code with the following comment:
// # ====================================================================
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
// # project. The module is, however, dual licensed under OpenSSL and
// # CRYPTOGAMS licenses depending on where you obtain it. For further
// # details see http://www.openssl.org/~appro/cryptogams/.
// # ====================================================================
// Code for the perl script that generates the ppc64 assembler
// can be found in the cryptogams repository at the link below. It is based on
// the original from openssl.
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91
// The differences in this and the original implementation are
// due to the calling conventions and initialization of constants.
// +build !gccgo,!purego
#include "textflag.h"
#define OUT R3
#define INP R4
#define LEN R5
#define KEY R6
#define CNT R7
#define TMP R15
#define CONSTBASE R16
#define BLOCKS R17
DATA consts<>+0x00(SB)/8, $0x3320646e61707865
DATA consts<>+0x08(SB)/8, $0x6b20657479622d32
DATA consts<>+0x10(SB)/8, $0x0000000000000001
DATA consts<>+0x18(SB)/8, $0x0000000000000000
DATA consts<>+0x20(SB)/8, $0x0000000000000004
DATA consts<>+0x28(SB)/8, $0x0000000000000000
DATA consts<>+0x30(SB)/8, $0x0a0b08090e0f0c0d
DATA consts<>+0x38(SB)/8, $0x0203000106070405
DATA consts<>+0x40(SB)/8, $0x090a0b080d0e0f0c
DATA consts<>+0x48(SB)/8, $0x0102030005060704
DATA consts<>+0x50(SB)/8, $0x6170786561707865
DATA consts<>+0x58(SB)/8, $0x6170786561707865
DATA consts<>+0x60(SB)/8, $0x3320646e3320646e
DATA consts<>+0x68(SB)/8, $0x3320646e3320646e
DATA consts<>+0x70(SB)/8, $0x79622d3279622d32
DATA consts<>+0x78(SB)/8, $0x79622d3279622d32
DATA consts<>+0x80(SB)/8, $0x6b2065746b206574
DATA consts<>+0x88(SB)/8, $0x6b2065746b206574
DATA consts<>+0x90(SB)/8, $0x0000000100000000
DATA consts<>+0x98(SB)/8, $0x0000000300000002
GLOBL consts<>(SB), RODATA, $0xa0
//func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40
MOVD out+0(FP), OUT
MOVD inp+8(FP), INP
MOVD len+16(FP), LEN
MOVD key+24(FP), KEY
MOVD counter+32(FP), CNT
// Addressing for constants
MOVD $consts<>+0x00(SB), CONSTBASE
MOVD $16, R8
MOVD $32, R9
MOVD $48, R10
MOVD $64, R11
SRD $6, LEN, BLOCKS
// V16
LXVW4X (CONSTBASE)(R0), VS48
ADD $80,CONSTBASE
// Load key into V17,V18
LXVW4X (KEY)(R0), VS49
LXVW4X (KEY)(R8), VS50
// Load CNT, NONCE into V19
LXVW4X (CNT)(R0), VS51
// Clear V27
VXOR V27, V27, V27
// V28
LXVW4X (CONSTBASE)(R11), VS60
// splat slot from V19 -> V26
VSPLTW $0, V19, V26
VSLDOI $4, V19, V27, V19
VSLDOI $12, V27, V19, V19
VADDUWM V26, V28, V26
MOVD $10, R14
MOVD R14, CTR
loop_outer_vsx:
// V0, V1, V2, V3
LXVW4X (R0)(CONSTBASE), VS32
LXVW4X (R8)(CONSTBASE), VS33
LXVW4X (R9)(CONSTBASE), VS34
LXVW4X (R10)(CONSTBASE), VS35
// splat values from V17, V18 into V4-V11
VSPLTW $0, V17, V4
VSPLTW $1, V17, V5
VSPLTW $2, V17, V6
VSPLTW $3, V17, V7
VSPLTW $0, V18, V8
VSPLTW $1, V18, V9
VSPLTW $2, V18, V10
VSPLTW $3, V18, V11
// VOR
VOR V26, V26, V12
// splat values from V19 -> V13, V14, V15
VSPLTW $1, V19, V13
VSPLTW $2, V19, V14
VSPLTW $3, V19, V15
// splat const values
VSPLTISW $-16, V27
VSPLTISW $12, V28
VSPLTISW $8, V29
VSPLTISW $7, V30
loop_vsx:
VADDUWM V0, V4, V0
VADDUWM V1, V5, V1
VADDUWM V2, V6, V2
VADDUWM V3, V7, V3
VXOR V12, V0, V12
VXOR V13, V1, V13
VXOR V14, V2, V14
VXOR V15, V3, V15
VRLW V12, V27, V12
VRLW V13, V27, V13
VRLW V14, V27, V14
VRLW V15, V27, V15
VADDUWM V8, V12, V8
VADDUWM V9, V13, V9
VADDUWM V10, V14, V10
VADDUWM V11, V15, V11
VXOR V4, V8, V4
VXOR V5, V9, V5
VXOR V6, V10, V6
VXOR V7, V11, V7
VRLW V4, V28, V4
VRLW V5, V28, V5
VRLW V6, V28, V6
VRLW V7, V28, V7
VADDUWM V0, V4, V0
VADDUWM V1, V5, V1
VADDUWM V2, V6, V2
VADDUWM V3, V7, V3
VXOR V12, V0, V12
VXOR V13, V1, V13
VXOR V14, V2, V14
VXOR V15, V3, V15
VRLW V12, V29, V12
VRLW V13, V29, V13
VRLW V14, V29, V14
VRLW V15, V29, V15
VADDUWM V8, V12, V8
VADDUWM V9, V13, V9
VADDUWM V10, V14, V10
VADDUWM V11, V15, V11
VXOR V4, V8, V4
VXOR V5, V9, V5
VXOR V6, V10, V6
VXOR V7, V11, V7
VRLW V4, V30, V4
VRLW V5, V30, V5
VRLW V6, V30, V6
VRLW V7, V30, V7
VADDUWM V0, V5, V0
VADDUWM V1, V6, V1
VADDUWM V2, V7, V2
VADDUWM V3, V4, V3
VXOR V15, V0, V15
VXOR V12, V1, V12
VXOR V13, V2, V13
VXOR V14, V3, V14
VRLW V15, V27, V15
VRLW V12, V27, V12
VRLW V13, V27, V13
VRLW V14, V27, V14
VADDUWM V10, V15, V10
VADDUWM V11, V12, V11
VADDUWM V8, V13, V8
VADDUWM V9, V14, V9
VXOR V5, V10, V5
VXOR V6, V11, V6
VXOR V7, V8, V7
VXOR V4, V9, V4
VRLW V5, V28, V5
VRLW V6, V28, V6
VRLW V7, V28, V7
VRLW V4, V28, V4
VADDUWM V0, V5, V0
VADDUWM V1, V6, V1
VADDUWM V2, V7, V2
VADDUWM V3, V4, V3
VXOR V15, V0, V15
VXOR V12, V1, V12
VXOR V13, V2, V13
VXOR V14, V3, V14
VRLW V15, V29, V15
VRLW V12, V29, V12
VRLW V13, V29, V13
VRLW V14, V29, V14
VADDUWM V10, V15, V10
VADDUWM V11, V12, V11
VADDUWM V8, V13, V8
VADDUWM V9, V14, V9
VXOR V5, V10, V5
VXOR V6, V11, V6
VXOR V7, V8, V7
VXOR V4, V9, V4
VRLW V5, V30, V5
VRLW V6, V30, V6
VRLW V7, V30, V7
VRLW V4, V30, V4
BC 16, LT, loop_vsx
VADDUWM V12, V26, V12
WORD $0x13600F8C // VMRGEW V0, V1, V27
WORD $0x13821F8C // VMRGEW V2, V3, V28
WORD $0x10000E8C // VMRGOW V0, V1, V0
WORD $0x10421E8C // VMRGOW V2, V3, V2
WORD $0x13A42F8C // VMRGEW V4, V5, V29
WORD $0x13C63F8C // VMRGEW V6, V7, V30
XXPERMDI VS32, VS34, $0, VS33
XXPERMDI VS32, VS34, $3, VS35
XXPERMDI VS59, VS60, $0, VS32
XXPERMDI VS59, VS60, $3, VS34
WORD $0x10842E8C // VMRGOW V4, V5, V4
WORD $0x10C63E8C // VMRGOW V6, V7, V6
WORD $0x13684F8C // VMRGEW V8, V9, V27
WORD $0x138A5F8C // VMRGEW V10, V11, V28
XXPERMDI VS36, VS38, $0, VS37
XXPERMDI VS36, VS38, $3, VS39
XXPERMDI VS61, VS62, $0, VS36
XXPERMDI VS61, VS62, $3, VS38
WORD $0x11084E8C // VMRGOW V8, V9, V8
WORD $0x114A5E8C // VMRGOW V10, V11, V10
WORD $0x13AC6F8C // VMRGEW V12, V13, V29
WORD $0x13CE7F8C // VMRGEW V14, V15, V30
XXPERMDI VS40, VS42, $0, VS41
XXPERMDI VS40, VS42, $3, VS43
XXPERMDI VS59, VS60, $0, VS40
XXPERMDI VS59, VS60, $3, VS42
WORD $0x118C6E8C // VMRGOW V12, V13, V12
WORD $0x11CE7E8C // VMRGOW V14, V15, V14
VSPLTISW $4, V27
VADDUWM V26, V27, V26
XXPERMDI VS44, VS46, $0, VS45
XXPERMDI VS44, VS46, $3, VS47
XXPERMDI VS61, VS62, $0, VS44
XXPERMDI VS61, VS62, $3, VS46
VADDUWM V0, V16, V0
VADDUWM V4, V17, V4
VADDUWM V8, V18, V8
VADDUWM V12, V19, V12
CMPU LEN, $64
BLT tail_vsx
// Bottom of loop
LXVW4X (INP)(R0), VS59
LXVW4X (INP)(R8), VS60
LXVW4X (INP)(R9), VS61
LXVW4X (INP)(R10), VS62
VXOR V27, V0, V27
VXOR V28, V4, V28
VXOR V29, V8, V29
VXOR V30, V12, V30
STXVW4X VS59, (OUT)(R0)
STXVW4X VS60, (OUT)(R8)
ADD $64, INP
STXVW4X VS61, (OUT)(R9)
ADD $-64, LEN
STXVW4X VS62, (OUT)(R10)
ADD $64, OUT
BEQ done_vsx
VADDUWM V1, V16, V0
VADDUWM V5, V17, V4
VADDUWM V9, V18, V8
VADDUWM V13, V19, V12
CMPU LEN, $64
BLT tail_vsx
LXVW4X (INP)(R0), VS59
LXVW4X (INP)(R8), VS60
LXVW4X (INP)(R9), VS61
LXVW4X (INP)(R10), VS62
VXOR V27, V0, V27
VXOR V28, V4, V28
VXOR V29, V8, V29
VXOR V30, V12, V30
STXVW4X VS59, (OUT)(R0)
STXVW4X VS60, (OUT)(R8)
ADD $64, INP
STXVW4X VS61, (OUT)(R9)
ADD $-64, LEN
STXVW4X VS62, (OUT)(V10)
ADD $64, OUT
BEQ done_vsx
VADDUWM V2, V16, V0
VADDUWM V6, V17, V4
VADDUWM V10, V18, V8
VADDUWM V14, V19, V12
CMPU LEN, $64
BLT tail_vsx
LXVW4X (INP)(R0), VS59
LXVW4X (INP)(R8), VS60
LXVW4X (INP)(R9), VS61
LXVW4X (INP)(R10), VS62
VXOR V27, V0, V27
VXOR V28, V4, V28
VXOR V29, V8, V29
VXOR V30, V12, V30
STXVW4X VS59, (OUT)(R0)
STXVW4X VS60, (OUT)(R8)
ADD $64, INP
STXVW4X VS61, (OUT)(R9)
ADD $-64, LEN
STXVW4X VS62, (OUT)(R10)
ADD $64, OUT
BEQ done_vsx
VADDUWM V3, V16, V0
VADDUWM V7, V17, V4
VADDUWM V11, V18, V8
VADDUWM V15, V19, V12
CMPU LEN, $64
BLT tail_vsx
LXVW4X (INP)(R0), VS59
LXVW4X (INP)(R8), VS60
LXVW4X (INP)(R9), VS61
LXVW4X (INP)(R10), VS62
VXOR V27, V0, V27
VXOR V28, V4, V28
VXOR V29, V8, V29
VXOR V30, V12, V30
STXVW4X VS59, (OUT)(R0)
STXVW4X VS60, (OUT)(R8)
ADD $64, INP
STXVW4X VS61, (OUT)(R9)
ADD $-64, LEN
STXVW4X VS62, (OUT)(R10)
ADD $64, OUT
MOVD $10, R14
MOVD R14, CTR
BNE loop_outer_vsx
done_vsx:
// Increment counter by number of 64 byte blocks
MOVD (CNT), R14
ADD BLOCKS, R14
MOVD R14, (CNT)
RET
tail_vsx:
ADD $32, R1, R11
MOVD LEN, CTR
// Save values on stack to copy from
STXVW4X VS32, (R11)(R0)
STXVW4X VS36, (R11)(R8)
STXVW4X VS40, (R11)(R9)
STXVW4X VS44, (R11)(R10)
ADD $-1, R11, R12
ADD $-1, INP
ADD $-1, OUT
looptail_vsx:
// Copying the result to OUT
// in bytes.
MOVBZU 1(R12), KEY
MOVBZU 1(INP), TMP
XOR KEY, TMP, KEY
MOVBU KEY, 1(OUT)
BC 16, LT, looptail_vsx
// Clear the stack values
STXVW4X VS48, (R11)(R0)
STXVW4X VS48, (R11)(R8)
STXVW4X VS48, (R11)(R9)
STXVW4X VS48, (R11)(R10)
BR done_vsx
-26
View File
@@ -1,26 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
package chacha20
import "golang.org/x/sys/cpu"
var haveAsm = cpu.S390X.HasVX
const bufSize = 256
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
// be called when the vector facility is available. Implementation in asm_s390x.s.
//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
if cpu.S390X.HasVX {
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
} else {
c.xorKeyStreamBlocksGeneric(dst, src)
}
}
-274
View File
@@ -1,274 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package chacha20
import (
"bytes"
"encoding/hex"
"fmt"
"math/rand"
"testing"
)
func _() {
// Assert that bufSize is a multiple of blockSize.
var b [1]byte
_ = b[bufSize%blockSize]
}
func hexDecode(s string) []byte {
ss, err := hex.DecodeString(s)
if err != nil {
panic(fmt.Sprintf("cannot decode input %#v: %v", s, err))
}
return ss
}
// Run the test cases with the input and output in different buffers.
func TestNoOverlap(t *testing.T) {
for _, c := range testVectors {
s, _ := NewUnauthenticatedCipher(hexDecode(c.key), hexDecode(c.nonce))
input := hexDecode(c.input)
output := make([]byte, len(input))
s.XORKeyStream(output, input)
got := hex.EncodeToString(output)
if got != c.output {
t.Errorf("length=%v: got %#v, want %#v", len(input), got, c.output)
}
}
}
// Run the test cases with the input and output overlapping entirely.
func TestOverlap(t *testing.T) {
for _, c := range testVectors {
s, _ := NewUnauthenticatedCipher(hexDecode(c.key), hexDecode(c.nonce))
data := hexDecode(c.input)
s.XORKeyStream(data, data)
got := hex.EncodeToString(data)
if got != c.output {
t.Errorf("length=%v: got %#v, want %#v", len(data), 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 {
data := hexDecode(c.input)
input := make([]byte, len(data)+max)
output := make([]byte, len(data)+max)
for i := 0; i < max; i++ { // input offsets
for j := 0; j < max; j++ { // output offsets
s, _ := NewUnauthenticatedCipher(hexDecode(c.key), hexDecode(c.nonce))
input := input[i : i+len(data)]
output := output[j : j+len(data)]
copy(input, data)
s.XORKeyStream(output, input)
got := hex.EncodeToString(output)
if got != c.output {
t.Errorf("length=%v: got %#v, want %#v", len(data), 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, _ := NewUnauthenticatedCipher(hexDecode(c.key), hexDecode(c.nonce))
input := hexDecode(c.input)
output := make([]byte, len(input))
// step through the buffers
i, step := 0, steps[rnd.Intn(len(steps))]
for i+step < len(input) {
s.XORKeyStream(output[i:i+step], input[i:i+step])
if i+step < len(input) && output[i+step] != 0 {
t.Errorf("length=%v, i=%v, step=%v: output overwritten", len(input), i, step)
}
i += step
step = steps[rnd.Intn(len(steps))]
}
// finish the encryption
s.XORKeyStream(output[i:], input[i:])
// ensure we tolerate a call with an empty input
s.XORKeyStream(output[len(output):], input[len(input):])
got := hex.EncodeToString(output)
if got != c.output {
t.Errorf("length=%v: got %#v, want %#v", len(input), got, c.output)
}
}
}
func TestSetCounter(t *testing.T) {
newCipher := func() *Cipher {
s, _ := NewUnauthenticatedCipher(make([]byte, KeySize), make([]byte, NonceSize))
return s
}
s := newCipher()
src := bytes.Repeat([]byte("test"), 32) // two 64-byte blocks
dst1 := make([]byte, len(src))
s.XORKeyStream(dst1, src)
// advance counter to 1 and xor second block
s = newCipher()
s.SetCounter(1)
dst2 := make([]byte, len(src))
s.XORKeyStream(dst2[64:], src[64:])
if !bytes.Equal(dst1[64:], dst2[64:]) {
t.Error("failed to produce identical output using SetCounter")
}
// test again with unaligned blocks; SetCounter should reset the buffer
s = newCipher()
s.XORKeyStream(dst1[:70], src[:70])
s = newCipher()
s.XORKeyStream([]byte{0}, []byte{0})
s.SetCounter(1)
s.XORKeyStream(dst2[64:70], src[64:70])
if !bytes.Equal(dst1[64:70], dst2[64:70]) {
t.Error("SetCounter did not reset buffer")
}
// advancing to a lower counter value should cause a panic
panics := func(fn func()) (p bool) {
defer func() { p = recover() != nil }()
fn()
return
}
if !panics(func() { s.SetCounter(0) }) {
t.Error("counter decreasing should trigger a panic")
}
}
func TestLastBlock(t *testing.T) {
panics := func(fn func()) (p bool) {
defer func() { p = recover() != nil }()
fn()
return
}
checkLastBlock := func(b []byte) {
t.Helper()
// Hardcoded result to check all implementations generate the same output.
lastBlock := "ace4cd09e294d1912d4ad205d06f95d9c2f2bfcf453e8753f128765b62215f4d" +
"92c74f2f626c6a640c0b1284d839ec81f1696281dafc3e684593937023b58b1d"
if got := hex.EncodeToString(b); got != lastBlock {
t.Errorf("wrong output for the last block, got %q, want %q", got, lastBlock)
}
}
// setting the counter to 0xffffffff and crypting multiple blocks should
// trigger a panic
s, _ := NewUnauthenticatedCipher(make([]byte, KeySize), make([]byte, NonceSize))
s.SetCounter(0xffffffff)
blocks := make([]byte, blockSize*2)
if !panics(func() { s.XORKeyStream(blocks, blocks) }) {
t.Error("crypting multiple blocks should trigger a panic")
}
// setting the counter to 0xffffffff - 1 and crypting two blocks should not
// trigger a panic
s, _ = NewUnauthenticatedCipher(make([]byte, KeySize), make([]byte, NonceSize))
s.SetCounter(0xffffffff - 1)
if panics(func() { s.XORKeyStream(blocks, blocks) }) {
t.Error("crypting the last blocks should not trigger a panic")
}
checkLastBlock(blocks[blockSize:])
// once all the keystream is spent, setting the counter should panic
if !panics(func() { s.SetCounter(0xffffffff) }) {
t.Error("setting the counter after overflow should trigger a panic")
}
// crypting a subsequent block *should* panic
block := make([]byte, blockSize)
if !panics(func() { s.XORKeyStream(block, block) }) {
t.Error("crypting after overflow should trigger a panic")
}
// if we crypt less than a full block, we should be able to crypt the rest
// in a subsequent call without panicking
s, _ = NewUnauthenticatedCipher(make([]byte, KeySize), make([]byte, NonceSize))
s.SetCounter(0xffffffff)
if panics(func() { s.XORKeyStream(block[:7], block[:7]) }) {
t.Error("crypting part of the last block should not trigger a panic")
}
if panics(func() { s.XORKeyStream(block[7:], block[7:]) }) {
t.Error("crypting part of the last block should not trigger a panic")
}
checkLastBlock(block)
// as before, a third call should trigger a panic because all keystream is spent
if !panics(func() { s.XORKeyStream(block[:1], block[:1]) }) {
t.Error("crypting after overflow should trigger a panic")
}
}
func benchmarkChaCha20(b *testing.B, step, count int) {
tot := step * count
src := make([]byte, tot)
dst := make([]byte, tot)
key := make([]byte, KeySize)
nonce := make([]byte, NonceSize)
b.SetBytes(int64(tot))
b.ResetTimer()
for i := 0; i < b.N; i++ {
c, _ := NewUnauthenticatedCipher(key, nonce)
for i := 0; i < tot; i += step {
c.XORKeyStream(dst[i:], src[i:i+step])
}
}
}
func BenchmarkChaCha20(b *testing.B) {
b.Run("64", func(b *testing.B) {
benchmarkChaCha20(b, 64, 1)
})
b.Run("256", func(b *testing.B) {
benchmarkChaCha20(b, 256, 1)
})
b.Run("10x25", func(b *testing.B) {
benchmarkChaCha20(b, 10, 25)
})
b.Run("4096", func(b *testing.B) {
benchmarkChaCha20(b, 256, 1)
})
b.Run("100x40", func(b *testing.B) {
benchmarkChaCha20(b, 100, 40)
})
b.Run("65536", func(b *testing.B) {
benchmarkChaCha20(b, 65536, 1)
})
b.Run("1000x65", func(b *testing.B) {
benchmarkChaCha20(b, 1000, 65)
})
}
func TestHChaCha20(t *testing.T) {
// See draft-irtf-cfrg-xchacha-00, Section 2.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, err := HChaCha20(key[:], nonce[:])
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(expected, result) {
t.Errorf("want %x, got %x", expected, result)
}
}
+12 -5
View File
@@ -2,13 +2,13 @@
// 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 and its
// extended nonce variant XChaCha20-Poly1305, as specified in RFC 8439 and
// draft-irtf-cfrg-xchacha-01.
// 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"
)
@@ -29,7 +29,7 @@ const (
)
type chacha20poly1305 struct {
key [KeySize]byte
key [8]uint32
}
// New returns a ChaCha20-Poly1305 AEAD that uses the given 256-bit key.
@@ -38,7 +38,14 @@ func New(key []byte) (cipher.AEAD, error) {
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
}
+11 -11
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build go1.7,amd64,!gccgo,!appengine
package chacha20poly1305
@@ -25,23 +25,23 @@ var (
// setupState writes a ChaCha20 input matrix to state. See
// https://tools.ietf.org/html/rfc7539#section-2.3.
func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
func setupState(state *[16]uint32, key *[8]uint32, nonce []byte) {
state[0] = 0x61707865
state[1] = 0x3320646e
state[2] = 0x79622d32
state[3] = 0x6b206574
state[4] = binary.LittleEndian.Uint32(key[0:4])
state[5] = binary.LittleEndian.Uint32(key[4:8])
state[6] = binary.LittleEndian.Uint32(key[8:12])
state[7] = binary.LittleEndian.Uint32(key[12:16])
state[8] = binary.LittleEndian.Uint32(key[16:20])
state[9] = binary.LittleEndian.Uint32(key[20:24])
state[10] = binary.LittleEndian.Uint32(key[24:28])
state[11] = binary.LittleEndian.Uint32(key[28:32])
state[4] = key[0]
state[5] = key[1]
state[6] = key[2]
state[7] = key[3]
state[8] = key[4]
state[9] = key[5]
state[10] = key[6]
state[11] = key[7]
state[12] = 0
state[13] = binary.LittleEndian.Uint32(nonce[0:4])
state[13] = binary.LittleEndian.Uint32(nonce[:4])
state[14] = binary.LittleEndian.Uint32(nonce[4:8])
state[15] = binary.LittleEndian.Uint32(nonce[8:12])
}
+1 -1
View File
@@ -4,7 +4,7 @@
// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
// +build !gccgo,!purego
// +build go1.7,amd64,!gccgo,!appengine
#include "textflag.h"
// General register allocation
+33 -33
View File
@@ -7,69 +7,69 @@ package chacha20poly1305
import (
"encoding/binary"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/internal/chacha20"
"golang.org/x/crypto/internal/subtle"
"golang.org/x/crypto/poly1305"
)
func writeWithPadding(p *poly1305.MAC, b []byte) {
p.Write(b)
if rem := len(b) % 16; rem != 0 {
var buf [16]byte
padLen := 16 - rem
p.Write(buf[:padLen])
}
}
func writeUint64(p *poly1305.MAC, n int) {
var buf [8]byte
binary.LittleEndian.PutUint64(buf[:], uint64(n))
p.Write(buf[:])
func roundTo16(n int) int {
return 16 * ((n + 15) / 16)
}
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
ciphertext, tag := out[:len(plaintext)], out[len(plaintext):]
if subtle.InexactOverlap(out, plaintext) {
panic("chacha20poly1305: invalid buffer overlap")
}
var polyKey [32]byte
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
s := chacha20.New(c.key, [3]uint32{
binary.LittleEndian.Uint32(nonce[0:4]),
binary.LittleEndian.Uint32(nonce[4:8]),
binary.LittleEndian.Uint32(nonce[8:12]),
})
s.XORKeyStream(polyKey[:], polyKey[:])
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
s.XORKeyStream(ciphertext, plaintext)
s.Advance() // skip the next 32 bytes
s.XORKeyStream(out, plaintext)
p := poly1305.New(&polyKey)
writeWithPadding(p, additionalData)
writeWithPadding(p, ciphertext)
writeUint64(p, len(additionalData))
writeUint64(p, len(plaintext))
p.Sum(tag[:0])
polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8)
copy(polyInput, additionalData)
copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)])
binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext)))
var tag [poly1305.TagSize]byte
poly1305.Sum(&tag, polyInput, &polyKey)
copy(out[len(plaintext):], tag[:])
return ret
}
func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
tag := ciphertext[len(ciphertext)-16:]
var tag [poly1305.TagSize]byte
copy(tag[:], ciphertext[len(ciphertext)-16:])
ciphertext = ciphertext[:len(ciphertext)-16]
var polyKey [32]byte
s, _ := chacha20.NewUnauthenticatedCipher(c.key[:], nonce)
s := chacha20.New(c.key, [3]uint32{
binary.LittleEndian.Uint32(nonce[0:4]),
binary.LittleEndian.Uint32(nonce[4:8]),
binary.LittleEndian.Uint32(nonce[8:12]),
})
s.XORKeyStream(polyKey[:], polyKey[:])
s.SetCounter(1) // set the counter to 1, skipping 32 bytes
s.Advance() // skip the next 32 bytes
p := poly1305.New(&polyKey)
writeWithPadding(p, additionalData)
writeWithPadding(p, ciphertext)
writeUint64(p, len(additionalData))
writeUint64(p, len(ciphertext))
polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8)
copy(polyInput, additionalData)
copy(polyInput[roundTo16(len(additionalData)):], ciphertext)
binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
ret, out := sliceForAppend(dst, len(ciphertext))
if subtle.InexactOverlap(out, ciphertext) {
panic("chacha20poly1305: invalid buffer overlap")
}
if !p.Verify(tag) {
if !poly1305.Verify(&tag, polyInput, &polyKey) {
for i := range out {
out[i] = 0
}
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 gccgo purego
// +build !amd64 !go1.7 gccgo appengine
package chacha20poly1305
+17 -30
View File
@@ -10,6 +10,7 @@ import (
cryptorand "crypto/rand"
"encoding/hex"
"fmt"
"log"
mathrand "math/rand"
"strconv"
"testing"
@@ -219,50 +220,36 @@ func BenchmarkChacha20Poly1305(b *testing.B) {
}
}
func ExampleNewX() {
// key should be randomly generated or derived from a function like Argon2.
key := make([]byte, KeySize)
if _, err := cryptorand.Read(key); err != nil {
panic(err)
}
var key = make([]byte, KeySize)
func ExampleNewX() {
aead, err := NewX(key)
if err != nil {
panic(err)
log.Fatalln("Failed to instantiate XChaCha20-Poly1305:", err)
}
// Encryption.
var encryptedMsg []byte
{
msg := []byte("Gophers, gophers, gophers everywhere!")
// Select a random nonce, and leave capacity for the ciphertext.
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(msg)+aead.Overhead())
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)
// Encrypt the message and append the ciphertext to the nonce.
encryptedMsg = aead.Seal(nonce, nonce, msg, nil)
}
// Decryption.
{
if len(encryptedMsg) < aead.NonceSize() {
panic("ciphertext too short")
}
// Split nonce and ciphertext.
nonce, ciphertext := encryptedMsg[:aead.NonceSize()], encryptedMsg[aead.NonceSize():]
// Decrypt the message and check it wasn't tampered with.
// Decryption.
plaintext, err := aead.Open(nil, nonce, ciphertext, nil)
if err != nil {
panic(err)
log.Fatalln("Failed to decrypt or authenticate message:", err)
}
fmt.Printf("%s\n", plaintext)
}
// Output: Gophers, gophers, gophers everywhere!
// Output: Attack at dawn.
// The eagle has landed.
// Gophers, gophers, gophers everywhere!
}
@@ -15,12 +15,11 @@ var chacha20Poly1305Tests = []struct {
"a0784d7a4716f3feb4f64e7f4b39bf04",
},
{
// https://tools.ietf.org/html/draft-irtf-cfrg-xchacha-01#appendix-A.3.1
"4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e",
"50515253c0c1c2c3c4c5c6c7",
"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
"404142434445464748494a4b4c4d4e4f5051525354555657",
"bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b4522f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff921f9664c97637da9768812f615c68b13b52ec0875924c1c7987947deafd8780acf49",
"070000004041424344454647",
"d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd0600691",
},
{
"1400000cebccee3bf561b292340fec60",
+29 -11
View File
@@ -6,13 +6,14 @@ package chacha20poly1305
import (
"crypto/cipher"
"encoding/binary"
"errors"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/internal/chacha20"
)
type xchacha20poly1305 struct {
key [KeySize]byte
key [8]uint32
}
// NewX returns a XChaCha20-Poly1305 AEAD that uses the given 256-bit key.
@@ -26,7 +27,14 @@ func NewX(key []byte) (cipher.AEAD, error) {
return nil, errors.New("chacha20poly1305: bad key length")
}
ret := new(xchacha20poly1305)
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
}
@@ -52,10 +60,15 @@ func (x *xchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) [
panic("chacha20poly1305: plaintext too large")
}
c := new(chacha20poly1305)
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
copy(c.key[:], hKey)
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])
@@ -74,10 +87,15 @@ func (x *xchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte)
panic("chacha20poly1305: ciphertext too large")
}
c := new(chacha20poly1305)
hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16])
copy(c.key[:], hKey)
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])
+3 -3
View File
@@ -81,7 +81,7 @@ func (b *Builder) AddASN1BigInt(n *big.Int) {
for i := range bytes {
bytes[i] ^= 0xff
}
if len(bytes) == 0 || bytes[0]&0x80 == 0 {
if bytes[0]&0x80 == 0 {
c.add(0xff)
}
c.add(bytes...)
@@ -230,12 +230,12 @@ func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
// String
// ReadASN1Boolean decodes an ASN.1 BOOLEAN and converts it to a boolean
// 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.BOOLEAN) || len(bytes) != 1 {
if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 {
return false
}
-37
View File
@@ -335,40 +335,3 @@ func TestReadASN1BitString(t *testing.T) {
}
}
}
func TestAddASN1BigInt(t *testing.T) {
x := big.NewInt(-1)
var b Builder
b.AddASN1BigInt(x)
got, err := b.Bytes()
if err != nil {
t.Fatalf("unexpected error adding -1: %v", err)
}
s := String(got)
var y big.Int
ok := s.ReadASN1Integer(&y)
if !ok || x.Cmp(&y) != 0 {
t.Errorf("unexpected bytes %v, want %v", &y, x)
}
}
func TestReadASN1Boolean(t *testing.T) {
testData := []struct {
in []byte
ok bool
out bool
}{
{[]byte{}, false, false},
{[]byte{0x01, 0x01, 0x00}, true, false},
{[]byte{0x01, 0x01, 0xff}, true, true},
{[]byte{0x01, 0x01, 0x01}, false, false},
}
for i, test := range testData {
in := String(test.in)
var out bool
ok := in.ReadASN1Boolean(&out)
if ok != test.ok || ok && (out != test.out) {
t.Errorf("#%d: in.ReadASN1Boolean() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
}
}
}
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
#define REDMASK51 0x0007FFFFFFFFFFFF
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine
// These constants cannot be encoded in non-MOVQ immediates.
// We access them directly from memory instead.
DATA ·_121666_213(SB)/8, $996687872
GLOBL ·_121666_213(SB), 8, $8
DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA
GLOBL ·_2P0(SB), 8, $8
DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE
GLOBL ·_2P1234(SB), 8, $8
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build amd64,!gccgo,!appengine
// func cswap(inout *[4][5]uint64, v uint64)
TEXT ·cswap(SB),7,$0
MOVQ inout+0(FP),DI
MOVQ v+8(FP),SI
SUBQ $1, SI
NOTQ SI
MOVQ SI, X15
PSHUFD $0x44, X15, X15
MOVOU 0(DI), X0
MOVOU 16(DI), X2
MOVOU 32(DI), X4
MOVOU 48(DI), X6
MOVOU 64(DI), X8
MOVOU 80(DI), X1
MOVOU 96(DI), X3
MOVOU 112(DI), X5
MOVOU 128(DI), X7
MOVOU 144(DI), X9
MOVO X1, X10
MOVO X3, X11
MOVO X5, X12
MOVO X7, X13
MOVO X9, X14
PXOR X0, X10
PXOR X2, X11
PXOR X4, X12
PXOR X6, X13
PXOR X8, X14
PAND X15, X10
PAND X15, X11
PAND X15, X12
PAND X15, X13
PAND X15, X14
PXOR X10, X0
PXOR X10, X1
PXOR X11, X2
PXOR X11, X3
PXOR X12, X4
PXOR X12, X5
PXOR X13, X6
PXOR X13, X7
PXOR X14, X8
PXOR X14, X9
MOVOU X0, 0(DI)
MOVOU X2, 16(DI)
MOVOU X4, 32(DI)
MOVOU X6, 48(DI)
MOVOU X8, 64(DI)
MOVOU X1, 80(DI)
MOVOU X3, 96(DI)
MOVOU X5, 112(DI)
MOVOU X7, 128(DI)
MOVOU X9, 144(DI)
RET
+818 -79
View File
@@ -1,95 +1,834 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package curve25519 provides an implementation of the X25519 function, which
// performs scalar multiplication on the elliptic curve known as Curve25519.
// See RFC 7748.
package curve25519 // import "golang.org/x/crypto/curve25519"
// We have an implementation in amd64 assembly so this code is only run on
// non-amd64 platforms. The amd64 assembly does not support gccgo.
// +build !amd64 gccgo appengine
package curve25519
import (
"crypto/subtle"
"fmt"
"encoding/binary"
)
// ScalarMult sets dst to the product scalar * point.
//
// Deprecated: when provided a low-order point, ScalarMult will set dst to all
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
// will return an error.
func ScalarMult(dst, scalar, point *[32]byte) {
scalarMult(dst, scalar, point)
}
// This code is a port of the public domain, "ref10" implementation of
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
// ScalarBaseMult sets dst to the product scalar * base where base is the
// standard generator.
//
// It is recommended to use the X25519 function with Basepoint instead, as
// copying into fixed size arrays can lead to unexpected bugs.
func ScalarBaseMult(dst, scalar *[32]byte) {
ScalarMult(dst, scalar, &basePoint)
}
// fieldElement represents an element of the field GF(2^255 - 19). An element
// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
// context.
type fieldElement [10]int32
const (
// ScalarSize is the size of the scalar input to X25519.
ScalarSize = 32
// PointSize is the size of the point input to X25519.
PointSize = 32
)
// Basepoint is the canonical Curve25519 generator.
var Basepoint []byte
var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
func init() { Basepoint = basePoint[:] }
func checkBasepoint() {
if subtle.ConstantTimeCompare(Basepoint, []byte{
0x09, 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,
}) != 1 {
panic("curve25519: global Basepoint value was modified")
func feZero(fe *fieldElement) {
for i := range fe {
fe[i] = 0
}
}
// X25519 returns the result of the scalar multiplication (scalar * point),
// according to RFC 7748, Section 5. scalar, point and the return value are
// slices of 32 bytes.
//
// scalar can be generated at random, for example with crypto/rand. point should
// be either Basepoint or the output of another X25519 call.
//
// If point is Basepoint (but not if it's a different slice with the same
// contents) a precomputed implementation might be used for performance.
func X25519(scalar, point []byte) ([]byte, error) {
// Outline the body of function, to let the allocation be inlined in the
// caller, and possibly avoid escaping to the heap.
var dst [32]byte
return x25519(&dst, scalar, point)
func feOne(fe *fieldElement) {
feZero(fe)
fe[0] = 1
}
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
var in [32]byte
if l := len(scalar); l != 32 {
return nil, fmt.Errorf("bad scalar length: %d, expected %d", l, 32)
func feAdd(dst, a, b *fieldElement) {
for i := range dst {
dst[i] = a[i] + b[i]
}
if l := len(point); l != 32 {
return nil, fmt.Errorf("bad point length: %d, expected %d", l, 32)
}
copy(in[:], scalar)
if &point[0] == &Basepoint[0] {
checkBasepoint()
ScalarBaseMult(dst, &in)
} else {
var base, zero [32]byte
copy(base[:], point)
ScalarMult(dst, &in, &base)
if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
return nil, fmt.Errorf("bad input point: low order point")
}
}
return dst[:], nil
}
func feSub(dst, a, b *fieldElement) {
for i := range dst {
dst[i] = a[i] - b[i]
}
}
func feCopy(dst, src *fieldElement) {
for i := range dst {
dst[i] = src[i]
}
}
// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
//
// Preconditions: b in {0,1}.
func feCSwap(f, g *fieldElement, b int32) {
b = -b
for i := range f {
t := b & (f[i] ^ g[i])
f[i] ^= t
g[i] ^= t
}
}
// load3 reads a 24-bit, little-endian value from in.
func load3(in []byte) int64 {
var r int64
r = int64(in[0])
r |= int64(in[1]) << 8
r |= int64(in[2]) << 16
return r
}
// load4 reads a 32-bit, little-endian value from in.
func load4(in []byte) int64 {
return int64(binary.LittleEndian.Uint32(in))
}
func feFromBytes(dst *fieldElement, src *[32]byte) {
h0 := load4(src[:])
h1 := load3(src[4:]) << 6
h2 := load3(src[7:]) << 5
h3 := load3(src[10:]) << 3
h4 := load3(src[13:]) << 2
h5 := load4(src[16:])
h6 := load3(src[20:]) << 7
h7 := load3(src[23:]) << 5
h8 := load3(src[26:]) << 4
h9 := (load3(src[29:]) & 0x7fffff) << 2
var carry [10]int64
carry[9] = (h9 + 1<<24) >> 25
h0 += carry[9] * 19
h9 -= carry[9] << 25
carry[1] = (h1 + 1<<24) >> 25
h2 += carry[1]
h1 -= carry[1] << 25
carry[3] = (h3 + 1<<24) >> 25
h4 += carry[3]
h3 -= carry[3] << 25
carry[5] = (h5 + 1<<24) >> 25
h6 += carry[5]
h5 -= carry[5] << 25
carry[7] = (h7 + 1<<24) >> 25
h8 += carry[7]
h7 -= carry[7] << 25
carry[0] = (h0 + 1<<25) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
carry[2] = (h2 + 1<<25) >> 26
h3 += carry[2]
h2 -= carry[2] << 26
carry[4] = (h4 + 1<<25) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[6] = (h6 + 1<<25) >> 26
h7 += carry[6]
h6 -= carry[6] << 26
carry[8] = (h8 + 1<<25) >> 26
h9 += carry[8]
h8 -= carry[8] << 26
dst[0] = int32(h0)
dst[1] = int32(h1)
dst[2] = int32(h2)
dst[3] = int32(h3)
dst[4] = int32(h4)
dst[5] = int32(h5)
dst[6] = int32(h6)
dst[7] = int32(h7)
dst[8] = int32(h8)
dst[9] = int32(h9)
}
// feToBytes marshals h to s.
// Preconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// Write p=2^255-19; q=floor(h/p).
// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
//
// Proof:
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
//
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
// Then 0<y<1.
//
// Write r=h-pq.
// Have 0<=r<=p-1=2^255-20.
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
//
// Write x=r+19(2^-255)r+y.
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
//
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
func feToBytes(s *[32]byte, h *fieldElement) {
var carry [10]int32
q := (19*h[9] + (1 << 24)) >> 25
q = (h[0] + q) >> 26
q = (h[1] + q) >> 25
q = (h[2] + q) >> 26
q = (h[3] + q) >> 25
q = (h[4] + q) >> 26
q = (h[5] + q) >> 25
q = (h[6] + q) >> 26
q = (h[7] + q) >> 25
q = (h[8] + q) >> 26
q = (h[9] + q) >> 25
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
h[0] += 19 * q
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
carry[0] = h[0] >> 26
h[1] += carry[0]
h[0] -= carry[0] << 26
carry[1] = h[1] >> 25
h[2] += carry[1]
h[1] -= carry[1] << 25
carry[2] = h[2] >> 26
h[3] += carry[2]
h[2] -= carry[2] << 26
carry[3] = h[3] >> 25
h[4] += carry[3]
h[3] -= carry[3] << 25
carry[4] = h[4] >> 26
h[5] += carry[4]
h[4] -= carry[4] << 26
carry[5] = h[5] >> 25
h[6] += carry[5]
h[5] -= carry[5] << 25
carry[6] = h[6] >> 26
h[7] += carry[6]
h[6] -= carry[6] << 26
carry[7] = h[7] >> 25
h[8] += carry[7]
h[7] -= carry[7] << 25
carry[8] = h[8] >> 26
h[9] += carry[8]
h[8] -= carry[8] << 26
carry[9] = h[9] >> 25
h[9] -= carry[9] << 25
// h10 = carry9
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
// evidently 2^255 h10-2^255 q = 0.
// Goal: Output h[0]+...+2^230 h[9].
s[0] = byte(h[0] >> 0)
s[1] = byte(h[0] >> 8)
s[2] = byte(h[0] >> 16)
s[3] = byte((h[0] >> 24) | (h[1] << 2))
s[4] = byte(h[1] >> 6)
s[5] = byte(h[1] >> 14)
s[6] = byte((h[1] >> 22) | (h[2] << 3))
s[7] = byte(h[2] >> 5)
s[8] = byte(h[2] >> 13)
s[9] = byte((h[2] >> 21) | (h[3] << 5))
s[10] = byte(h[3] >> 3)
s[11] = byte(h[3] >> 11)
s[12] = byte((h[3] >> 19) | (h[4] << 6))
s[13] = byte(h[4] >> 2)
s[14] = byte(h[4] >> 10)
s[15] = byte(h[4] >> 18)
s[16] = byte(h[5] >> 0)
s[17] = byte(h[5] >> 8)
s[18] = byte(h[5] >> 16)
s[19] = byte((h[5] >> 24) | (h[6] << 1))
s[20] = byte(h[6] >> 7)
s[21] = byte(h[6] >> 15)
s[22] = byte((h[6] >> 23) | (h[7] << 3))
s[23] = byte(h[7] >> 5)
s[24] = byte(h[7] >> 13)
s[25] = byte((h[7] >> 21) | (h[8] << 4))
s[26] = byte(h[8] >> 4)
s[27] = byte(h[8] >> 12)
s[28] = byte((h[8] >> 20) | (h[9] << 6))
s[29] = byte(h[9] >> 2)
s[30] = byte(h[9] >> 10)
s[31] = byte(h[9] >> 18)
}
// feMul calculates h = f * g
// Can overlap h with f or g.
//
// Preconditions:
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// Notes on implementation strategy:
//
// Using schoolbook multiplication.
// Karatsuba would save a little in some cost models.
//
// Most multiplications by 2 and 19 are 32-bit precomputations;
// cheaper than 64-bit postcomputations.
//
// There is one remaining multiplication by 19 in the carry chain;
// one *19 precomputation can be merged into this,
// but the resulting data flow is considerably less clean.
//
// There are 12 carries below.
// 10 of them are 2-way parallelizable and vectorizable.
// Can get away with 11 carries, but then data flow is much deeper.
//
// With tighter constraints on inputs can squeeze carries into int32.
func feMul(h, f, g *fieldElement) {
f0 := f[0]
f1 := f[1]
f2 := f[2]
f3 := f[3]
f4 := f[4]
f5 := f[5]
f6 := f[6]
f7 := f[7]
f8 := f[8]
f9 := f[9]
g0 := g[0]
g1 := g[1]
g2 := g[2]
g3 := g[3]
g4 := g[4]
g5 := g[5]
g6 := g[6]
g7 := g[7]
g8 := g[8]
g9 := g[9]
g1_19 := 19 * g1 // 1.4*2^29
g2_19 := 19 * g2 // 1.4*2^30; still ok
g3_19 := 19 * g3
g4_19 := 19 * g4
g5_19 := 19 * g5
g6_19 := 19 * g6
g7_19 := 19 * g7
g8_19 := 19 * g8
g9_19 := 19 * g9
f1_2 := 2 * f1
f3_2 := 2 * f3
f5_2 := 2 * f5
f7_2 := 2 * f7
f9_2 := 2 * f9
f0g0 := int64(f0) * int64(g0)
f0g1 := int64(f0) * int64(g1)
f0g2 := int64(f0) * int64(g2)
f0g3 := int64(f0) * int64(g3)
f0g4 := int64(f0) * int64(g4)
f0g5 := int64(f0) * int64(g5)
f0g6 := int64(f0) * int64(g6)
f0g7 := int64(f0) * int64(g7)
f0g8 := int64(f0) * int64(g8)
f0g9 := int64(f0) * int64(g9)
f1g0 := int64(f1) * int64(g0)
f1g1_2 := int64(f1_2) * int64(g1)
f1g2 := int64(f1) * int64(g2)
f1g3_2 := int64(f1_2) * int64(g3)
f1g4 := int64(f1) * int64(g4)
f1g5_2 := int64(f1_2) * int64(g5)
f1g6 := int64(f1) * int64(g6)
f1g7_2 := int64(f1_2) * int64(g7)
f1g8 := int64(f1) * int64(g8)
f1g9_38 := int64(f1_2) * int64(g9_19)
f2g0 := int64(f2) * int64(g0)
f2g1 := int64(f2) * int64(g1)
f2g2 := int64(f2) * int64(g2)
f2g3 := int64(f2) * int64(g3)
f2g4 := int64(f2) * int64(g4)
f2g5 := int64(f2) * int64(g5)
f2g6 := int64(f2) * int64(g6)
f2g7 := int64(f2) * int64(g7)
f2g8_19 := int64(f2) * int64(g8_19)
f2g9_19 := int64(f2) * int64(g9_19)
f3g0 := int64(f3) * int64(g0)
f3g1_2 := int64(f3_2) * int64(g1)
f3g2 := int64(f3) * int64(g2)
f3g3_2 := int64(f3_2) * int64(g3)
f3g4 := int64(f3) * int64(g4)
f3g5_2 := int64(f3_2) * int64(g5)
f3g6 := int64(f3) * int64(g6)
f3g7_38 := int64(f3_2) * int64(g7_19)
f3g8_19 := int64(f3) * int64(g8_19)
f3g9_38 := int64(f3_2) * int64(g9_19)
f4g0 := int64(f4) * int64(g0)
f4g1 := int64(f4) * int64(g1)
f4g2 := int64(f4) * int64(g2)
f4g3 := int64(f4) * int64(g3)
f4g4 := int64(f4) * int64(g4)
f4g5 := int64(f4) * int64(g5)
f4g6_19 := int64(f4) * int64(g6_19)
f4g7_19 := int64(f4) * int64(g7_19)
f4g8_19 := int64(f4) * int64(g8_19)
f4g9_19 := int64(f4) * int64(g9_19)
f5g0 := int64(f5) * int64(g0)
f5g1_2 := int64(f5_2) * int64(g1)
f5g2 := int64(f5) * int64(g2)
f5g3_2 := int64(f5_2) * int64(g3)
f5g4 := int64(f5) * int64(g4)
f5g5_38 := int64(f5_2) * int64(g5_19)
f5g6_19 := int64(f5) * int64(g6_19)
f5g7_38 := int64(f5_2) * int64(g7_19)
f5g8_19 := int64(f5) * int64(g8_19)
f5g9_38 := int64(f5_2) * int64(g9_19)
f6g0 := int64(f6) * int64(g0)
f6g1 := int64(f6) * int64(g1)
f6g2 := int64(f6) * int64(g2)
f6g3 := int64(f6) * int64(g3)
f6g4_19 := int64(f6) * int64(g4_19)
f6g5_19 := int64(f6) * int64(g5_19)
f6g6_19 := int64(f6) * int64(g6_19)
f6g7_19 := int64(f6) * int64(g7_19)
f6g8_19 := int64(f6) * int64(g8_19)
f6g9_19 := int64(f6) * int64(g9_19)
f7g0 := int64(f7) * int64(g0)
f7g1_2 := int64(f7_2) * int64(g1)
f7g2 := int64(f7) * int64(g2)
f7g3_38 := int64(f7_2) * int64(g3_19)
f7g4_19 := int64(f7) * int64(g4_19)
f7g5_38 := int64(f7_2) * int64(g5_19)
f7g6_19 := int64(f7) * int64(g6_19)
f7g7_38 := int64(f7_2) * int64(g7_19)
f7g8_19 := int64(f7) * int64(g8_19)
f7g9_38 := int64(f7_2) * int64(g9_19)
f8g0 := int64(f8) * int64(g0)
f8g1 := int64(f8) * int64(g1)
f8g2_19 := int64(f8) * int64(g2_19)
f8g3_19 := int64(f8) * int64(g3_19)
f8g4_19 := int64(f8) * int64(g4_19)
f8g5_19 := int64(f8) * int64(g5_19)
f8g6_19 := int64(f8) * int64(g6_19)
f8g7_19 := int64(f8) * int64(g7_19)
f8g8_19 := int64(f8) * int64(g8_19)
f8g9_19 := int64(f8) * int64(g9_19)
f9g0 := int64(f9) * int64(g0)
f9g1_38 := int64(f9_2) * int64(g1_19)
f9g2_19 := int64(f9) * int64(g2_19)
f9g3_38 := int64(f9_2) * int64(g3_19)
f9g4_19 := int64(f9) * int64(g4_19)
f9g5_38 := int64(f9_2) * int64(g5_19)
f9g6_19 := int64(f9) * int64(g6_19)
f9g7_38 := int64(f9_2) * int64(g7_19)
f9g8_19 := int64(f9) * int64(g8_19)
f9g9_38 := int64(f9_2) * int64(g9_19)
h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
var carry [10]int64
// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
// i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
// i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
// |h0| <= 2^25
// |h4| <= 2^25
// |h1| <= 1.51*2^58
// |h5| <= 1.51*2^58
carry[1] = (h1 + (1 << 24)) >> 25
h2 += carry[1]
h1 -= carry[1] << 25
carry[5] = (h5 + (1 << 24)) >> 25
h6 += carry[5]
h5 -= carry[5] << 25
// |h1| <= 2^24; from now on fits into int32
// |h5| <= 2^24; from now on fits into int32
// |h2| <= 1.21*2^59
// |h6| <= 1.21*2^59
carry[2] = (h2 + (1 << 25)) >> 26
h3 += carry[2]
h2 -= carry[2] << 26
carry[6] = (h6 + (1 << 25)) >> 26
h7 += carry[6]
h6 -= carry[6] << 26
// |h2| <= 2^25; from now on fits into int32 unchanged
// |h6| <= 2^25; from now on fits into int32 unchanged
// |h3| <= 1.51*2^58
// |h7| <= 1.51*2^58
carry[3] = (h3 + (1 << 24)) >> 25
h4 += carry[3]
h3 -= carry[3] << 25
carry[7] = (h7 + (1 << 24)) >> 25
h8 += carry[7]
h7 -= carry[7] << 25
// |h3| <= 2^24; from now on fits into int32 unchanged
// |h7| <= 2^24; from now on fits into int32 unchanged
// |h4| <= 1.52*2^33
// |h8| <= 1.52*2^33
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[8] = (h8 + (1 << 25)) >> 26
h9 += carry[8]
h8 -= carry[8] << 26
// |h4| <= 2^25; from now on fits into int32 unchanged
// |h8| <= 2^25; from now on fits into int32 unchanged
// |h5| <= 1.01*2^24
// |h9| <= 1.51*2^58
carry[9] = (h9 + (1 << 24)) >> 25
h0 += carry[9] * 19
h9 -= carry[9] << 25
// |h9| <= 2^24; from now on fits into int32 unchanged
// |h0| <= 1.8*2^37
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
// |h0| <= 2^25; from now on fits into int32 unchanged
// |h1| <= 1.01*2^24
h[0] = int32(h0)
h[1] = int32(h1)
h[2] = int32(h2)
h[3] = int32(h3)
h[4] = int32(h4)
h[5] = int32(h5)
h[6] = int32(h6)
h[7] = int32(h7)
h[8] = int32(h8)
h[9] = int32(h9)
}
// feSquare calculates h = f*f. Can overlap h with f.
//
// Preconditions:
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
func feSquare(h, f *fieldElement) {
f0 := f[0]
f1 := f[1]
f2 := f[2]
f3 := f[3]
f4 := f[4]
f5 := f[5]
f6 := f[6]
f7 := f[7]
f8 := f[8]
f9 := f[9]
f0_2 := 2 * f0
f1_2 := 2 * f1
f2_2 := 2 * f2
f3_2 := 2 * f3
f4_2 := 2 * f4
f5_2 := 2 * f5
f6_2 := 2 * f6
f7_2 := 2 * f7
f5_38 := 38 * f5 // 1.31*2^30
f6_19 := 19 * f6 // 1.31*2^30
f7_38 := 38 * f7 // 1.31*2^30
f8_19 := 19 * f8 // 1.31*2^30
f9_38 := 38 * f9 // 1.31*2^30
f0f0 := int64(f0) * int64(f0)
f0f1_2 := int64(f0_2) * int64(f1)
f0f2_2 := int64(f0_2) * int64(f2)
f0f3_2 := int64(f0_2) * int64(f3)
f0f4_2 := int64(f0_2) * int64(f4)
f0f5_2 := int64(f0_2) * int64(f5)
f0f6_2 := int64(f0_2) * int64(f6)
f0f7_2 := int64(f0_2) * int64(f7)
f0f8_2 := int64(f0_2) * int64(f8)
f0f9_2 := int64(f0_2) * int64(f9)
f1f1_2 := int64(f1_2) * int64(f1)
f1f2_2 := int64(f1_2) * int64(f2)
f1f3_4 := int64(f1_2) * int64(f3_2)
f1f4_2 := int64(f1_2) * int64(f4)
f1f5_4 := int64(f1_2) * int64(f5_2)
f1f6_2 := int64(f1_2) * int64(f6)
f1f7_4 := int64(f1_2) * int64(f7_2)
f1f8_2 := int64(f1_2) * int64(f8)
f1f9_76 := int64(f1_2) * int64(f9_38)
f2f2 := int64(f2) * int64(f2)
f2f3_2 := int64(f2_2) * int64(f3)
f2f4_2 := int64(f2_2) * int64(f4)
f2f5_2 := int64(f2_2) * int64(f5)
f2f6_2 := int64(f2_2) * int64(f6)
f2f7_2 := int64(f2_2) * int64(f7)
f2f8_38 := int64(f2_2) * int64(f8_19)
f2f9_38 := int64(f2) * int64(f9_38)
f3f3_2 := int64(f3_2) * int64(f3)
f3f4_2 := int64(f3_2) * int64(f4)
f3f5_4 := int64(f3_2) * int64(f5_2)
f3f6_2 := int64(f3_2) * int64(f6)
f3f7_76 := int64(f3_2) * int64(f7_38)
f3f8_38 := int64(f3_2) * int64(f8_19)
f3f9_76 := int64(f3_2) * int64(f9_38)
f4f4 := int64(f4) * int64(f4)
f4f5_2 := int64(f4_2) * int64(f5)
f4f6_38 := int64(f4_2) * int64(f6_19)
f4f7_38 := int64(f4) * int64(f7_38)
f4f8_38 := int64(f4_2) * int64(f8_19)
f4f9_38 := int64(f4) * int64(f9_38)
f5f5_38 := int64(f5) * int64(f5_38)
f5f6_38 := int64(f5_2) * int64(f6_19)
f5f7_76 := int64(f5_2) * int64(f7_38)
f5f8_38 := int64(f5_2) * int64(f8_19)
f5f9_76 := int64(f5_2) * int64(f9_38)
f6f6_19 := int64(f6) * int64(f6_19)
f6f7_38 := int64(f6) * int64(f7_38)
f6f8_38 := int64(f6_2) * int64(f8_19)
f6f9_38 := int64(f6) * int64(f9_38)
f7f7_38 := int64(f7) * int64(f7_38)
f7f8_38 := int64(f7_2) * int64(f8_19)
f7f9_76 := int64(f7_2) * int64(f9_38)
f8f8_19 := int64(f8) * int64(f8_19)
f8f9_38 := int64(f8) * int64(f9_38)
f9f9_38 := int64(f9) * int64(f9_38)
h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
var carry [10]int64
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[1] = (h1 + (1 << 24)) >> 25
h2 += carry[1]
h1 -= carry[1] << 25
carry[5] = (h5 + (1 << 24)) >> 25
h6 += carry[5]
h5 -= carry[5] << 25
carry[2] = (h2 + (1 << 25)) >> 26
h3 += carry[2]
h2 -= carry[2] << 26
carry[6] = (h6 + (1 << 25)) >> 26
h7 += carry[6]
h6 -= carry[6] << 26
carry[3] = (h3 + (1 << 24)) >> 25
h4 += carry[3]
h3 -= carry[3] << 25
carry[7] = (h7 + (1 << 24)) >> 25
h8 += carry[7]
h7 -= carry[7] << 25
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[8] = (h8 + (1 << 25)) >> 26
h9 += carry[8]
h8 -= carry[8] << 26
carry[9] = (h9 + (1 << 24)) >> 25
h0 += carry[9] * 19
h9 -= carry[9] << 25
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
h[0] = int32(h0)
h[1] = int32(h1)
h[2] = int32(h2)
h[3] = int32(h3)
h[4] = int32(h4)
h[5] = int32(h5)
h[6] = int32(h6)
h[7] = int32(h7)
h[8] = int32(h8)
h[9] = int32(h9)
}
// feMul121666 calculates h = f * 121666. Can overlap h with f.
//
// Preconditions:
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
func feMul121666(h, f *fieldElement) {
h0 := int64(f[0]) * 121666
h1 := int64(f[1]) * 121666
h2 := int64(f[2]) * 121666
h3 := int64(f[3]) * 121666
h4 := int64(f[4]) * 121666
h5 := int64(f[5]) * 121666
h6 := int64(f[6]) * 121666
h7 := int64(f[7]) * 121666
h8 := int64(f[8]) * 121666
h9 := int64(f[9]) * 121666
var carry [10]int64
carry[9] = (h9 + (1 << 24)) >> 25
h0 += carry[9] * 19
h9 -= carry[9] << 25
carry[1] = (h1 + (1 << 24)) >> 25
h2 += carry[1]
h1 -= carry[1] << 25
carry[3] = (h3 + (1 << 24)) >> 25
h4 += carry[3]
h3 -= carry[3] << 25
carry[5] = (h5 + (1 << 24)) >> 25
h6 += carry[5]
h5 -= carry[5] << 25
carry[7] = (h7 + (1 << 24)) >> 25
h8 += carry[7]
h7 -= carry[7] << 25
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
carry[2] = (h2 + (1 << 25)) >> 26
h3 += carry[2]
h2 -= carry[2] << 26
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[6] = (h6 + (1 << 25)) >> 26
h7 += carry[6]
h6 -= carry[6] << 26
carry[8] = (h8 + (1 << 25)) >> 26
h9 += carry[8]
h8 -= carry[8] << 26
h[0] = int32(h0)
h[1] = int32(h1)
h[2] = int32(h2)
h[3] = int32(h3)
h[4] = int32(h4)
h[5] = int32(h5)
h[6] = int32(h6)
h[7] = int32(h7)
h[8] = int32(h8)
h[9] = int32(h9)
}
// feInvert sets out = z^-1.
func feInvert(out, z *fieldElement) {
var t0, t1, t2, t3 fieldElement
var i int
feSquare(&t0, z)
for i = 1; i < 1; i++ {
feSquare(&t0, &t0)
}
feSquare(&t1, &t0)
for i = 1; i < 2; i++ {
feSquare(&t1, &t1)
}
feMul(&t1, z, &t1)
feMul(&t0, &t0, &t1)
feSquare(&t2, &t0)
for i = 1; i < 1; i++ {
feSquare(&t2, &t2)
}
feMul(&t1, &t1, &t2)
feSquare(&t2, &t1)
for i = 1; i < 5; i++ {
feSquare(&t2, &t2)
}
feMul(&t1, &t2, &t1)
feSquare(&t2, &t1)
for i = 1; i < 10; i++ {
feSquare(&t2, &t2)
}
feMul(&t2, &t2, &t1)
feSquare(&t3, &t2)
for i = 1; i < 20; i++ {
feSquare(&t3, &t3)
}
feMul(&t2, &t3, &t2)
feSquare(&t2, &t2)
for i = 1; i < 10; i++ {
feSquare(&t2, &t2)
}
feMul(&t1, &t2, &t1)
feSquare(&t2, &t1)
for i = 1; i < 50; i++ {
feSquare(&t2, &t2)
}
feMul(&t2, &t2, &t1)
feSquare(&t3, &t2)
for i = 1; i < 100; i++ {
feSquare(&t3, &t3)
}
feMul(&t2, &t3, &t2)
feSquare(&t2, &t2)
for i = 1; i < 50; i++ {
feSquare(&t2, &t2)
}
feMul(&t1, &t2, &t1)
feSquare(&t1, &t1)
for i = 1; i < 5; i++ {
feSquare(&t1, &t1)
}
feMul(out, &t1, &t0)
}
func scalarMult(out, in, base *[32]byte) {
var e [32]byte
copy(e[:], in[:])
e[0] &= 248
e[31] &= 127
e[31] |= 64
var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
feFromBytes(&x1, base)
feOne(&x2)
feCopy(&x3, &x1)
feOne(&z3)
swap := int32(0)
for pos := 254; pos >= 0; pos-- {
b := e[pos/8] >> uint(pos&7)
b &= 1
swap ^= int32(b)
feCSwap(&x2, &x3, swap)
feCSwap(&z2, &z3, swap)
swap = int32(b)
feSub(&tmp0, &x3, &z3)
feSub(&tmp1, &x2, &z2)
feAdd(&x2, &x2, &z2)
feAdd(&z2, &x3, &z3)
feMul(&z3, &tmp0, &x2)
feMul(&z2, &z2, &tmp1)
feSquare(&tmp0, &tmp1)
feSquare(&tmp1, &x2)
feAdd(&x3, &z3, &z2)
feSub(&z2, &z3, &z2)
feMul(&x2, &tmp1, &tmp0)
feSub(&tmp1, &tmp1, &tmp0)
feSquare(&z2, &z2)
feMul121666(&z3, &tmp1)
feSquare(&x3, &x3)
feAdd(&tmp0, &tmp0, &z3)
feMul(&z3, &x1, &z2)
feMul(&z2, &tmp1, &tmp0)
}
feCSwap(&x2, &x3, swap)
feCSwap(&z2, &z3, swap)
feInvert(&z2, &z2)
feMul(&x2, &x2, &z2)
feToBytes(out, &x2)
}
-828
View File
@@ -1,828 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package curve25519
import "encoding/binary"
// This code is a port of the public domain, "ref10" implementation of
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
// fieldElement represents an element of the field GF(2^255 - 19). An element
// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
// context.
type fieldElement [10]int32
func feZero(fe *fieldElement) {
for i := range fe {
fe[i] = 0
}
}
func feOne(fe *fieldElement) {
feZero(fe)
fe[0] = 1
}
func feAdd(dst, a, b *fieldElement) {
for i := range dst {
dst[i] = a[i] + b[i]
}
}
func feSub(dst, a, b *fieldElement) {
for i := range dst {
dst[i] = a[i] - b[i]
}
}
func feCopy(dst, src *fieldElement) {
for i := range dst {
dst[i] = src[i]
}
}
// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
//
// Preconditions: b in {0,1}.
func feCSwap(f, g *fieldElement, b int32) {
b = -b
for i := range f {
t := b & (f[i] ^ g[i])
f[i] ^= t
g[i] ^= t
}
}
// load3 reads a 24-bit, little-endian value from in.
func load3(in []byte) int64 {
var r int64
r = int64(in[0])
r |= int64(in[1]) << 8
r |= int64(in[2]) << 16
return r
}
// load4 reads a 32-bit, little-endian value from in.
func load4(in []byte) int64 {
return int64(binary.LittleEndian.Uint32(in))
}
func feFromBytes(dst *fieldElement, src *[32]byte) {
h0 := load4(src[:])
h1 := load3(src[4:]) << 6
h2 := load3(src[7:]) << 5
h3 := load3(src[10:]) << 3
h4 := load3(src[13:]) << 2
h5 := load4(src[16:])
h6 := load3(src[20:]) << 7
h7 := load3(src[23:]) << 5
h8 := load3(src[26:]) << 4
h9 := (load3(src[29:]) & 0x7fffff) << 2
var carry [10]int64
carry[9] = (h9 + 1<<24) >> 25
h0 += carry[9] * 19
h9 -= carry[9] << 25
carry[1] = (h1 + 1<<24) >> 25
h2 += carry[1]
h1 -= carry[1] << 25
carry[3] = (h3 + 1<<24) >> 25
h4 += carry[3]
h3 -= carry[3] << 25
carry[5] = (h5 + 1<<24) >> 25
h6 += carry[5]
h5 -= carry[5] << 25
carry[7] = (h7 + 1<<24) >> 25
h8 += carry[7]
h7 -= carry[7] << 25
carry[0] = (h0 + 1<<25) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
carry[2] = (h2 + 1<<25) >> 26
h3 += carry[2]
h2 -= carry[2] << 26
carry[4] = (h4 + 1<<25) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[6] = (h6 + 1<<25) >> 26
h7 += carry[6]
h6 -= carry[6] << 26
carry[8] = (h8 + 1<<25) >> 26
h9 += carry[8]
h8 -= carry[8] << 26
dst[0] = int32(h0)
dst[1] = int32(h1)
dst[2] = int32(h2)
dst[3] = int32(h3)
dst[4] = int32(h4)
dst[5] = int32(h5)
dst[6] = int32(h6)
dst[7] = int32(h7)
dst[8] = int32(h8)
dst[9] = int32(h9)
}
// feToBytes marshals h to s.
// Preconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// Write p=2^255-19; q=floor(h/p).
// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
//
// Proof:
// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
//
// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
// Then 0<y<1.
//
// Write r=h-pq.
// Have 0<=r<=p-1=2^255-20.
// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
//
// Write x=r+19(2^-255)r+y.
// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
//
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
func feToBytes(s *[32]byte, h *fieldElement) {
var carry [10]int32
q := (19*h[9] + (1 << 24)) >> 25
q = (h[0] + q) >> 26
q = (h[1] + q) >> 25
q = (h[2] + q) >> 26
q = (h[3] + q) >> 25
q = (h[4] + q) >> 26
q = (h[5] + q) >> 25
q = (h[6] + q) >> 26
q = (h[7] + q) >> 25
q = (h[8] + q) >> 26
q = (h[9] + q) >> 25
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
h[0] += 19 * q
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
carry[0] = h[0] >> 26
h[1] += carry[0]
h[0] -= carry[0] << 26
carry[1] = h[1] >> 25
h[2] += carry[1]
h[1] -= carry[1] << 25
carry[2] = h[2] >> 26
h[3] += carry[2]
h[2] -= carry[2] << 26
carry[3] = h[3] >> 25
h[4] += carry[3]
h[3] -= carry[3] << 25
carry[4] = h[4] >> 26
h[5] += carry[4]
h[4] -= carry[4] << 26
carry[5] = h[5] >> 25
h[6] += carry[5]
h[5] -= carry[5] << 25
carry[6] = h[6] >> 26
h[7] += carry[6]
h[6] -= carry[6] << 26
carry[7] = h[7] >> 25
h[8] += carry[7]
h[7] -= carry[7] << 25
carry[8] = h[8] >> 26
h[9] += carry[8]
h[8] -= carry[8] << 26
carry[9] = h[9] >> 25
h[9] -= carry[9] << 25
// h10 = carry9
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
// evidently 2^255 h10-2^255 q = 0.
// Goal: Output h[0]+...+2^230 h[9].
s[0] = byte(h[0] >> 0)
s[1] = byte(h[0] >> 8)
s[2] = byte(h[0] >> 16)
s[3] = byte((h[0] >> 24) | (h[1] << 2))
s[4] = byte(h[1] >> 6)
s[5] = byte(h[1] >> 14)
s[6] = byte((h[1] >> 22) | (h[2] << 3))
s[7] = byte(h[2] >> 5)
s[8] = byte(h[2] >> 13)
s[9] = byte((h[2] >> 21) | (h[3] << 5))
s[10] = byte(h[3] >> 3)
s[11] = byte(h[3] >> 11)
s[12] = byte((h[3] >> 19) | (h[4] << 6))
s[13] = byte(h[4] >> 2)
s[14] = byte(h[4] >> 10)
s[15] = byte(h[4] >> 18)
s[16] = byte(h[5] >> 0)
s[17] = byte(h[5] >> 8)
s[18] = byte(h[5] >> 16)
s[19] = byte((h[5] >> 24) | (h[6] << 1))
s[20] = byte(h[6] >> 7)
s[21] = byte(h[6] >> 15)
s[22] = byte((h[6] >> 23) | (h[7] << 3))
s[23] = byte(h[7] >> 5)
s[24] = byte(h[7] >> 13)
s[25] = byte((h[7] >> 21) | (h[8] << 4))
s[26] = byte(h[8] >> 4)
s[27] = byte(h[8] >> 12)
s[28] = byte((h[8] >> 20) | (h[9] << 6))
s[29] = byte(h[9] >> 2)
s[30] = byte(h[9] >> 10)
s[31] = byte(h[9] >> 18)
}
// feMul calculates h = f * g
// Can overlap h with f or g.
//
// Preconditions:
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
//
// Notes on implementation strategy:
//
// Using schoolbook multiplication.
// Karatsuba would save a little in some cost models.
//
// Most multiplications by 2 and 19 are 32-bit precomputations;
// cheaper than 64-bit postcomputations.
//
// There is one remaining multiplication by 19 in the carry chain;
// one *19 precomputation can be merged into this,
// but the resulting data flow is considerably less clean.
//
// There are 12 carries below.
// 10 of them are 2-way parallelizable and vectorizable.
// Can get away with 11 carries, but then data flow is much deeper.
//
// With tighter constraints on inputs can squeeze carries into int32.
func feMul(h, f, g *fieldElement) {
f0 := f[0]
f1 := f[1]
f2 := f[2]
f3 := f[3]
f4 := f[4]
f5 := f[5]
f6 := f[6]
f7 := f[7]
f8 := f[8]
f9 := f[9]
g0 := g[0]
g1 := g[1]
g2 := g[2]
g3 := g[3]
g4 := g[4]
g5 := g[5]
g6 := g[6]
g7 := g[7]
g8 := g[8]
g9 := g[9]
g1_19 := 19 * g1 // 1.4*2^29
g2_19 := 19 * g2 // 1.4*2^30; still ok
g3_19 := 19 * g3
g4_19 := 19 * g4
g5_19 := 19 * g5
g6_19 := 19 * g6
g7_19 := 19 * g7
g8_19 := 19 * g8
g9_19 := 19 * g9
f1_2 := 2 * f1
f3_2 := 2 * f3
f5_2 := 2 * f5
f7_2 := 2 * f7
f9_2 := 2 * f9
f0g0 := int64(f0) * int64(g0)
f0g1 := int64(f0) * int64(g1)
f0g2 := int64(f0) * int64(g2)
f0g3 := int64(f0) * int64(g3)
f0g4 := int64(f0) * int64(g4)
f0g5 := int64(f0) * int64(g5)
f0g6 := int64(f0) * int64(g6)
f0g7 := int64(f0) * int64(g7)
f0g8 := int64(f0) * int64(g8)
f0g9 := int64(f0) * int64(g9)
f1g0 := int64(f1) * int64(g0)
f1g1_2 := int64(f1_2) * int64(g1)
f1g2 := int64(f1) * int64(g2)
f1g3_2 := int64(f1_2) * int64(g3)
f1g4 := int64(f1) * int64(g4)
f1g5_2 := int64(f1_2) * int64(g5)
f1g6 := int64(f1) * int64(g6)
f1g7_2 := int64(f1_2) * int64(g7)
f1g8 := int64(f1) * int64(g8)
f1g9_38 := int64(f1_2) * int64(g9_19)
f2g0 := int64(f2) * int64(g0)
f2g1 := int64(f2) * int64(g1)
f2g2 := int64(f2) * int64(g2)
f2g3 := int64(f2) * int64(g3)
f2g4 := int64(f2) * int64(g4)
f2g5 := int64(f2) * int64(g5)
f2g6 := int64(f2) * int64(g6)
f2g7 := int64(f2) * int64(g7)
f2g8_19 := int64(f2) * int64(g8_19)
f2g9_19 := int64(f2) * int64(g9_19)
f3g0 := int64(f3) * int64(g0)
f3g1_2 := int64(f3_2) * int64(g1)
f3g2 := int64(f3) * int64(g2)
f3g3_2 := int64(f3_2) * int64(g3)
f3g4 := int64(f3) * int64(g4)
f3g5_2 := int64(f3_2) * int64(g5)
f3g6 := int64(f3) * int64(g6)
f3g7_38 := int64(f3_2) * int64(g7_19)
f3g8_19 := int64(f3) * int64(g8_19)
f3g9_38 := int64(f3_2) * int64(g9_19)
f4g0 := int64(f4) * int64(g0)
f4g1 := int64(f4) * int64(g1)
f4g2 := int64(f4) * int64(g2)
f4g3 := int64(f4) * int64(g3)
f4g4 := int64(f4) * int64(g4)
f4g5 := int64(f4) * int64(g5)
f4g6_19 := int64(f4) * int64(g6_19)
f4g7_19 := int64(f4) * int64(g7_19)
f4g8_19 := int64(f4) * int64(g8_19)
f4g9_19 := int64(f4) * int64(g9_19)
f5g0 := int64(f5) * int64(g0)
f5g1_2 := int64(f5_2) * int64(g1)
f5g2 := int64(f5) * int64(g2)
f5g3_2 := int64(f5_2) * int64(g3)
f5g4 := int64(f5) * int64(g4)
f5g5_38 := int64(f5_2) * int64(g5_19)
f5g6_19 := int64(f5) * int64(g6_19)
f5g7_38 := int64(f5_2) * int64(g7_19)
f5g8_19 := int64(f5) * int64(g8_19)
f5g9_38 := int64(f5_2) * int64(g9_19)
f6g0 := int64(f6) * int64(g0)
f6g1 := int64(f6) * int64(g1)
f6g2 := int64(f6) * int64(g2)
f6g3 := int64(f6) * int64(g3)
f6g4_19 := int64(f6) * int64(g4_19)
f6g5_19 := int64(f6) * int64(g5_19)
f6g6_19 := int64(f6) * int64(g6_19)
f6g7_19 := int64(f6) * int64(g7_19)
f6g8_19 := int64(f6) * int64(g8_19)
f6g9_19 := int64(f6) * int64(g9_19)
f7g0 := int64(f7) * int64(g0)
f7g1_2 := int64(f7_2) * int64(g1)
f7g2 := int64(f7) * int64(g2)
f7g3_38 := int64(f7_2) * int64(g3_19)
f7g4_19 := int64(f7) * int64(g4_19)
f7g5_38 := int64(f7_2) * int64(g5_19)
f7g6_19 := int64(f7) * int64(g6_19)
f7g7_38 := int64(f7_2) * int64(g7_19)
f7g8_19 := int64(f7) * int64(g8_19)
f7g9_38 := int64(f7_2) * int64(g9_19)
f8g0 := int64(f8) * int64(g0)
f8g1 := int64(f8) * int64(g1)
f8g2_19 := int64(f8) * int64(g2_19)
f8g3_19 := int64(f8) * int64(g3_19)
f8g4_19 := int64(f8) * int64(g4_19)
f8g5_19 := int64(f8) * int64(g5_19)
f8g6_19 := int64(f8) * int64(g6_19)
f8g7_19 := int64(f8) * int64(g7_19)
f8g8_19 := int64(f8) * int64(g8_19)
f8g9_19 := int64(f8) * int64(g9_19)
f9g0 := int64(f9) * int64(g0)
f9g1_38 := int64(f9_2) * int64(g1_19)
f9g2_19 := int64(f9) * int64(g2_19)
f9g3_38 := int64(f9_2) * int64(g3_19)
f9g4_19 := int64(f9) * int64(g4_19)
f9g5_38 := int64(f9_2) * int64(g5_19)
f9g6_19 := int64(f9) * int64(g6_19)
f9g7_38 := int64(f9_2) * int64(g7_19)
f9g8_19 := int64(f9) * int64(g8_19)
f9g9_38 := int64(f9_2) * int64(g9_19)
h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
var carry [10]int64
// |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
// i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
// |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
// i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
// |h0| <= 2^25
// |h4| <= 2^25
// |h1| <= 1.51*2^58
// |h5| <= 1.51*2^58
carry[1] = (h1 + (1 << 24)) >> 25
h2 += carry[1]
h1 -= carry[1] << 25
carry[5] = (h5 + (1 << 24)) >> 25
h6 += carry[5]
h5 -= carry[5] << 25
// |h1| <= 2^24; from now on fits into int32
// |h5| <= 2^24; from now on fits into int32
// |h2| <= 1.21*2^59
// |h6| <= 1.21*2^59
carry[2] = (h2 + (1 << 25)) >> 26
h3 += carry[2]
h2 -= carry[2] << 26
carry[6] = (h6 + (1 << 25)) >> 26
h7 += carry[6]
h6 -= carry[6] << 26
// |h2| <= 2^25; from now on fits into int32 unchanged
// |h6| <= 2^25; from now on fits into int32 unchanged
// |h3| <= 1.51*2^58
// |h7| <= 1.51*2^58
carry[3] = (h3 + (1 << 24)) >> 25
h4 += carry[3]
h3 -= carry[3] << 25
carry[7] = (h7 + (1 << 24)) >> 25
h8 += carry[7]
h7 -= carry[7] << 25
// |h3| <= 2^24; from now on fits into int32 unchanged
// |h7| <= 2^24; from now on fits into int32 unchanged
// |h4| <= 1.52*2^33
// |h8| <= 1.52*2^33
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[8] = (h8 + (1 << 25)) >> 26
h9 += carry[8]
h8 -= carry[8] << 26
// |h4| <= 2^25; from now on fits into int32 unchanged
// |h8| <= 2^25; from now on fits into int32 unchanged
// |h5| <= 1.01*2^24
// |h9| <= 1.51*2^58
carry[9] = (h9 + (1 << 24)) >> 25
h0 += carry[9] * 19
h9 -= carry[9] << 25
// |h9| <= 2^24; from now on fits into int32 unchanged
// |h0| <= 1.8*2^37
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
// |h0| <= 2^25; from now on fits into int32 unchanged
// |h1| <= 1.01*2^24
h[0] = int32(h0)
h[1] = int32(h1)
h[2] = int32(h2)
h[3] = int32(h3)
h[4] = int32(h4)
h[5] = int32(h5)
h[6] = int32(h6)
h[7] = int32(h7)
h[8] = int32(h8)
h[9] = int32(h9)
}
// feSquare calculates h = f*f. Can overlap h with f.
//
// Preconditions:
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
func feSquare(h, f *fieldElement) {
f0 := f[0]
f1 := f[1]
f2 := f[2]
f3 := f[3]
f4 := f[4]
f5 := f[5]
f6 := f[6]
f7 := f[7]
f8 := f[8]
f9 := f[9]
f0_2 := 2 * f0
f1_2 := 2 * f1
f2_2 := 2 * f2
f3_2 := 2 * f3
f4_2 := 2 * f4
f5_2 := 2 * f5
f6_2 := 2 * f6
f7_2 := 2 * f7
f5_38 := 38 * f5 // 1.31*2^30
f6_19 := 19 * f6 // 1.31*2^30
f7_38 := 38 * f7 // 1.31*2^30
f8_19 := 19 * f8 // 1.31*2^30
f9_38 := 38 * f9 // 1.31*2^30
f0f0 := int64(f0) * int64(f0)
f0f1_2 := int64(f0_2) * int64(f1)
f0f2_2 := int64(f0_2) * int64(f2)
f0f3_2 := int64(f0_2) * int64(f3)
f0f4_2 := int64(f0_2) * int64(f4)
f0f5_2 := int64(f0_2) * int64(f5)
f0f6_2 := int64(f0_2) * int64(f6)
f0f7_2 := int64(f0_2) * int64(f7)
f0f8_2 := int64(f0_2) * int64(f8)
f0f9_2 := int64(f0_2) * int64(f9)
f1f1_2 := int64(f1_2) * int64(f1)
f1f2_2 := int64(f1_2) * int64(f2)
f1f3_4 := int64(f1_2) * int64(f3_2)
f1f4_2 := int64(f1_2) * int64(f4)
f1f5_4 := int64(f1_2) * int64(f5_2)
f1f6_2 := int64(f1_2) * int64(f6)
f1f7_4 := int64(f1_2) * int64(f7_2)
f1f8_2 := int64(f1_2) * int64(f8)
f1f9_76 := int64(f1_2) * int64(f9_38)
f2f2 := int64(f2) * int64(f2)
f2f3_2 := int64(f2_2) * int64(f3)
f2f4_2 := int64(f2_2) * int64(f4)
f2f5_2 := int64(f2_2) * int64(f5)
f2f6_2 := int64(f2_2) * int64(f6)
f2f7_2 := int64(f2_2) * int64(f7)
f2f8_38 := int64(f2_2) * int64(f8_19)
f2f9_38 := int64(f2) * int64(f9_38)
f3f3_2 := int64(f3_2) * int64(f3)
f3f4_2 := int64(f3_2) * int64(f4)
f3f5_4 := int64(f3_2) * int64(f5_2)
f3f6_2 := int64(f3_2) * int64(f6)
f3f7_76 := int64(f3_2) * int64(f7_38)
f3f8_38 := int64(f3_2) * int64(f8_19)
f3f9_76 := int64(f3_2) * int64(f9_38)
f4f4 := int64(f4) * int64(f4)
f4f5_2 := int64(f4_2) * int64(f5)
f4f6_38 := int64(f4_2) * int64(f6_19)
f4f7_38 := int64(f4) * int64(f7_38)
f4f8_38 := int64(f4_2) * int64(f8_19)
f4f9_38 := int64(f4) * int64(f9_38)
f5f5_38 := int64(f5) * int64(f5_38)
f5f6_38 := int64(f5_2) * int64(f6_19)
f5f7_76 := int64(f5_2) * int64(f7_38)
f5f8_38 := int64(f5_2) * int64(f8_19)
f5f9_76 := int64(f5_2) * int64(f9_38)
f6f6_19 := int64(f6) * int64(f6_19)
f6f7_38 := int64(f6) * int64(f7_38)
f6f8_38 := int64(f6_2) * int64(f8_19)
f6f9_38 := int64(f6) * int64(f9_38)
f7f7_38 := int64(f7) * int64(f7_38)
f7f8_38 := int64(f7_2) * int64(f8_19)
f7f9_76 := int64(f7_2) * int64(f9_38)
f8f8_19 := int64(f8) * int64(f8_19)
f8f9_38 := int64(f8) * int64(f9_38)
f9f9_38 := int64(f9) * int64(f9_38)
h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
var carry [10]int64
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[1] = (h1 + (1 << 24)) >> 25
h2 += carry[1]
h1 -= carry[1] << 25
carry[5] = (h5 + (1 << 24)) >> 25
h6 += carry[5]
h5 -= carry[5] << 25
carry[2] = (h2 + (1 << 25)) >> 26
h3 += carry[2]
h2 -= carry[2] << 26
carry[6] = (h6 + (1 << 25)) >> 26
h7 += carry[6]
h6 -= carry[6] << 26
carry[3] = (h3 + (1 << 24)) >> 25
h4 += carry[3]
h3 -= carry[3] << 25
carry[7] = (h7 + (1 << 24)) >> 25
h8 += carry[7]
h7 -= carry[7] << 25
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[8] = (h8 + (1 << 25)) >> 26
h9 += carry[8]
h8 -= carry[8] << 26
carry[9] = (h9 + (1 << 24)) >> 25
h0 += carry[9] * 19
h9 -= carry[9] << 25
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
h[0] = int32(h0)
h[1] = int32(h1)
h[2] = int32(h2)
h[3] = int32(h3)
h[4] = int32(h4)
h[5] = int32(h5)
h[6] = int32(h6)
h[7] = int32(h7)
h[8] = int32(h8)
h[9] = int32(h9)
}
// feMul121666 calculates h = f * 121666. Can overlap h with f.
//
// Preconditions:
// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
//
// Postconditions:
// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
func feMul121666(h, f *fieldElement) {
h0 := int64(f[0]) * 121666
h1 := int64(f[1]) * 121666
h2 := int64(f[2]) * 121666
h3 := int64(f[3]) * 121666
h4 := int64(f[4]) * 121666
h5 := int64(f[5]) * 121666
h6 := int64(f[6]) * 121666
h7 := int64(f[7]) * 121666
h8 := int64(f[8]) * 121666
h9 := int64(f[9]) * 121666
var carry [10]int64
carry[9] = (h9 + (1 << 24)) >> 25
h0 += carry[9] * 19
h9 -= carry[9] << 25
carry[1] = (h1 + (1 << 24)) >> 25
h2 += carry[1]
h1 -= carry[1] << 25
carry[3] = (h3 + (1 << 24)) >> 25
h4 += carry[3]
h3 -= carry[3] << 25
carry[5] = (h5 + (1 << 24)) >> 25
h6 += carry[5]
h5 -= carry[5] << 25
carry[7] = (h7 + (1 << 24)) >> 25
h8 += carry[7]
h7 -= carry[7] << 25
carry[0] = (h0 + (1 << 25)) >> 26
h1 += carry[0]
h0 -= carry[0] << 26
carry[2] = (h2 + (1 << 25)) >> 26
h3 += carry[2]
h2 -= carry[2] << 26
carry[4] = (h4 + (1 << 25)) >> 26
h5 += carry[4]
h4 -= carry[4] << 26
carry[6] = (h6 + (1 << 25)) >> 26
h7 += carry[6]
h6 -= carry[6] << 26
carry[8] = (h8 + (1 << 25)) >> 26
h9 += carry[8]
h8 -= carry[8] << 26
h[0] = int32(h0)
h[1] = int32(h1)
h[2] = int32(h2)
h[3] = int32(h3)
h[4] = int32(h4)
h[5] = int32(h5)
h[6] = int32(h6)
h[7] = int32(h7)
h[8] = int32(h8)
h[9] = int32(h9)
}
// feInvert sets out = z^-1.
func feInvert(out, z *fieldElement) {
var t0, t1, t2, t3 fieldElement
var i int
feSquare(&t0, z)
for i = 1; i < 1; i++ {
feSquare(&t0, &t0)
}
feSquare(&t1, &t0)
for i = 1; i < 2; i++ {
feSquare(&t1, &t1)
}
feMul(&t1, z, &t1)
feMul(&t0, &t0, &t1)
feSquare(&t2, &t0)
for i = 1; i < 1; i++ {
feSquare(&t2, &t2)
}
feMul(&t1, &t1, &t2)
feSquare(&t2, &t1)
for i = 1; i < 5; i++ {
feSquare(&t2, &t2)
}
feMul(&t1, &t2, &t1)
feSquare(&t2, &t1)
for i = 1; i < 10; i++ {
feSquare(&t2, &t2)
}
feMul(&t2, &t2, &t1)
feSquare(&t3, &t2)
for i = 1; i < 20; i++ {
feSquare(&t3, &t3)
}
feMul(&t2, &t3, &t2)
feSquare(&t2, &t2)
for i = 1; i < 10; i++ {
feSquare(&t2, &t2)
}
feMul(&t1, &t2, &t1)
feSquare(&t2, &t1)
for i = 1; i < 50; i++ {
feSquare(&t2, &t2)
}
feMul(&t2, &t2, &t1)
feSquare(&t3, &t2)
for i = 1; i < 100; i++ {
feSquare(&t3, &t3)
}
feMul(&t2, &t3, &t2)
feSquare(&t2, &t2)
for i = 1; i < 50; i++ {
feSquare(&t2, &t2)
}
feMul(&t1, &t2, &t1)
feSquare(&t1, &t1)
for i = 1; i < 5; i++ {
feSquare(&t1, &t1)
}
feMul(out, &t1, &t0)
}
func scalarMultGeneric(out, in, base *[32]byte) {
var e [32]byte
copy(e[:], in[:])
e[0] &= 248
e[31] &= 127
e[31] |= 64
var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
feFromBytes(&x1, base)
feOne(&x2)
feCopy(&x3, &x1)
feOne(&z3)
swap := int32(0)
for pos := 254; pos >= 0; pos-- {
b := e[pos/8] >> uint(pos&7)
b &= 1
swap ^= int32(b)
feCSwap(&x2, &x3, swap)
feCSwap(&z2, &z3, swap)
swap = int32(b)
feSub(&tmp0, &x3, &z3)
feSub(&tmp1, &x2, &z2)
feAdd(&x2, &x2, &z2)
feAdd(&z2, &x3, &z3)
feMul(&z3, &tmp0, &x2)
feMul(&z2, &z2, &tmp1)
feSquare(&tmp0, &tmp1)
feSquare(&tmp1, &x2)
feAdd(&x3, &z3, &z2)
feSub(&z2, &z3, &z2)
feMul(&x2, &tmp1, &tmp0)
feSub(&tmp1, &tmp1, &tmp0)
feSquare(&z2, &z2)
feMul121666(&z3, &tmp1)
feSquare(&x3, &x3)
feAdd(&tmp0, &tmp0, &z3)
feMul(&z3, &x1, &z2)
feMul(&z2, &tmp1, &tmp0)
}
feCSwap(&x2, &x3, swap)
feCSwap(&z2, &z3, swap)
feInvert(&z2, &z2)
feMul(&x2, &x2, &z2)
feToBytes(out, &x2)
}
-11
View File
@@ -1,11 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64 gccgo appengine purego
package curve25519
func scalarMult(out, in, base *[32]byte) {
scalarMultGeneric(out, in, base)
}
+9 -40
View File
@@ -13,58 +13,27 @@ import (
const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"
func TestX25519Basepoint(t *testing.T) {
x := make([]byte, 32)
x[0] = 1
func TestBaseScalarMult(t *testing.T) {
var a, b [32]byte
in := &a
out := &b
a[0] = 1
for i := 0; i < 200; i++ {
var err error
x, err = X25519(x, Basepoint)
if err != nil {
t.Fatal(err)
}
ScalarBaseMult(out, in)
in, out = out, in
}
result := fmt.Sprintf("%x", x)
result := fmt.Sprintf("%x", in[:])
if result != expectedHex {
t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
}
}
func TestLowOrderPoints(t *testing.T) {
scalar := make([]byte, ScalarSize)
if _, err := rand.Read(scalar); err != nil {
t.Fatal(err)
}
for i, p := range lowOrderPoints {
out, err := X25519(scalar, p)
if err == nil {
t.Errorf("%d: expected error, got nil", i)
}
if out != nil {
t.Errorf("%d: expected nil output, got %x", i, out)
}
}
}
func TestTestVectors(t *testing.T) {
t.Run("Generic", func(t *testing.T) { testTestVectors(t, scalarMultGeneric) })
t.Run("Native", func(t *testing.T) { testTestVectors(t, ScalarMult) })
t.Run("X25519", func(t *testing.T) {
testTestVectors(t, func(dst, scalar, point *[32]byte) {
out, err := X25519(scalar[:], point[:])
if err != nil {
t.Fatal(err)
}
copy(dst[:], out)
})
})
}
func testTestVectors(t *testing.T, scalarMult func(dst, scalar, point *[32]byte)) {
for _, tv := range testVectors {
var got [32]byte
scalarMult(&got, &tv.In, &tv.Base)
ScalarMult(&got, &tv.In, &tv.Base)
if !bytes.Equal(got[:], tv.Expect[:]) {
t.Logf(" in = %x", tv.In)
t.Logf(" base = %x", tv.Base)
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package curve25519 provides an implementation of scalar multiplication on
// the elliptic curve known as curve25519. See https://cr.yp.to/ecdh.html
package curve25519 // import "golang.org/x/crypto/curve25519"
// basePoint is the x coordinate of the generator of the curve.
var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
// ScalarMult sets dst to the product in*base where dst and base are the x
// coordinates of group points and all values are in little-endian form.
func ScalarMult(dst, in, base *[32]byte) {
scalarMult(dst, in, base)
}
// ScalarBaseMult sets dst to the product in*base where dst and base are the x
// coordinates of group points, base is the standard generator and all values
// are in little-endian form.
func ScalarBaseMult(dst, in *[32]byte) {
ScalarMult(dst, in, &basePoint)
}
+73
View File
@@ -0,0 +1,73 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func freeze(inout *[5]uint64)
TEXT ·freeze(SB),7,$0-8
MOVQ inout+0(FP), DI
MOVQ 0(DI),SI
MOVQ 8(DI),DX
MOVQ 16(DI),CX
MOVQ 24(DI),R8
MOVQ 32(DI),R9
MOVQ $REDMASK51,AX
MOVQ AX,R10
SUBQ $18,R10
MOVQ $3,R11
REDUCELOOP:
MOVQ SI,R12
SHRQ $51,R12
ANDQ AX,SI
ADDQ R12,DX
MOVQ DX,R12
SHRQ $51,R12
ANDQ AX,DX
ADDQ R12,CX
MOVQ CX,R12
SHRQ $51,R12
ANDQ AX,CX
ADDQ R12,R8
MOVQ R8,R12
SHRQ $51,R12
ANDQ AX,R8
ADDQ R12,R9
MOVQ R9,R12
SHRQ $51,R12
ANDQ AX,R9
IMUL3Q $19,R12,R12
ADDQ R12,SI
SUBQ $1,R11
JA REDUCELOOP
MOVQ $1,R12
CMPQ R10,SI
CMOVQLT R11,R12
CMPQ AX,DX
CMOVQNE R11,R12
CMPQ AX,CX
CMOVQNE R11,R12
CMPQ AX,R8
CMOVQNE R11,R12
CMPQ AX,R9
CMOVQNE R11,R12
NEGQ R12
ANDQ R12,AX
ANDQ R12,R10
SUBQ R10,SI
SUBQ AX,DX
SUBQ AX,CX
SUBQ AX,R8
SUBQ AX,R9
MOVQ SI,0(DI)
MOVQ DX,8(DI)
MOVQ CX,16(DI)
MOVQ R8,24(DI)
MOVQ R9,32(DI)
RET
@@ -5,84 +5,9 @@
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine,!purego
// +build amd64,!gccgo,!appengine
#define REDMASK51 0x0007FFFFFFFFFFFF
// These constants cannot be encoded in non-MOVQ immediates.
// We access them directly from memory instead.
DATA ·_121666_213(SB)/8, $996687872
GLOBL ·_121666_213(SB), 8, $8
DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA
GLOBL ·_2P0(SB), 8, $8
DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE
GLOBL ·_2P1234(SB), 8, $8
// func freeze(inout *[5]uint64)
TEXT ·freeze(SB),7,$0-8
MOVQ inout+0(FP), DI
MOVQ 0(DI),SI
MOVQ 8(DI),DX
MOVQ 16(DI),CX
MOVQ 24(DI),R8
MOVQ 32(DI),R9
MOVQ $REDMASK51,AX
MOVQ AX,R10
SUBQ $18,R10
MOVQ $3,R11
REDUCELOOP:
MOVQ SI,R12
SHRQ $51,R12
ANDQ AX,SI
ADDQ R12,DX
MOVQ DX,R12
SHRQ $51,R12
ANDQ AX,DX
ADDQ R12,CX
MOVQ CX,R12
SHRQ $51,R12
ANDQ AX,CX
ADDQ R12,R8
MOVQ R8,R12
SHRQ $51,R12
ANDQ AX,R8
ADDQ R12,R9
MOVQ R9,R12
SHRQ $51,R12
ANDQ AX,R9
IMUL3Q $19,R12,R12
ADDQ R12,SI
SUBQ $1,R11
JA REDUCELOOP
MOVQ $1,R12
CMPQ R10,SI
CMOVQLT R11,R12
CMPQ AX,DX
CMOVQNE R11,R12
CMPQ AX,CX
CMOVQNE R11,R12
CMPQ AX,R8
CMOVQNE R11,R12
CMPQ AX,R9
CMOVQNE R11,R12
NEGQ R12
ANDQ R12,AX
ANDQ R12,R10
SUBQ R10,SI
SUBQ AX,DX
SUBQ AX,CX
SUBQ AX,R8
SUBQ AX,R9
MOVQ SI,0(DI)
MOVQ DX,8(DI)
MOVQ CX,16(DI)
MOVQ R8,24(DI)
MOVQ R9,32(DI)
RET
#include "const_amd64.h"
// func ladderstep(inout *[5][5]uint64)
TEXT ·ladderstep(SB),0,$296-8
@@ -1450,344 +1375,3 @@ TEXT ·ladderstep(SB),0,$296-8
MOVQ AX,104(DI)
MOVQ R10,112(DI)
RET
// func cswap(inout *[4][5]uint64, v uint64)
TEXT ·cswap(SB),7,$0
MOVQ inout+0(FP),DI
MOVQ v+8(FP),SI
SUBQ $1, SI
NOTQ SI
MOVQ SI, X15
PSHUFD $0x44, X15, X15
MOVOU 0(DI), X0
MOVOU 16(DI), X2
MOVOU 32(DI), X4
MOVOU 48(DI), X6
MOVOU 64(DI), X8
MOVOU 80(DI), X1
MOVOU 96(DI), X3
MOVOU 112(DI), X5
MOVOU 128(DI), X7
MOVOU 144(DI), X9
MOVO X1, X10
MOVO X3, X11
MOVO X5, X12
MOVO X7, X13
MOVO X9, X14
PXOR X0, X10
PXOR X2, X11
PXOR X4, X12
PXOR X6, X13
PXOR X8, X14
PAND X15, X10
PAND X15, X11
PAND X15, X12
PAND X15, X13
PAND X15, X14
PXOR X10, X0
PXOR X10, X1
PXOR X11, X2
PXOR X11, X3
PXOR X12, X4
PXOR X12, X5
PXOR X13, X6
PXOR X13, X7
PXOR X14, X8
PXOR X14, X9
MOVOU X0, 0(DI)
MOVOU X2, 16(DI)
MOVOU X4, 32(DI)
MOVOU X6, 48(DI)
MOVOU X8, 64(DI)
MOVOU X1, 80(DI)
MOVOU X3, 96(DI)
MOVOU X5, 112(DI)
MOVOU X7, 128(DI)
MOVOU X9, 144(DI)
RET
// func mul(dest, a, b *[5]uint64)
TEXT ·mul(SB),0,$16-24
MOVQ dest+0(FP), DI
MOVQ a+8(FP), SI
MOVQ b+16(FP), DX
MOVQ DX,CX
MOVQ 24(SI),DX
IMUL3Q $19,DX,AX
MOVQ AX,0(SP)
MULQ 16(CX)
MOVQ AX,R8
MOVQ DX,R9
MOVQ 32(SI),DX
IMUL3Q $19,DX,AX
MOVQ AX,8(SP)
MULQ 8(CX)
ADDQ AX,R8
ADCQ DX,R9
MOVQ 0(SI),AX
MULQ 0(CX)
ADDQ AX,R8
ADCQ DX,R9
MOVQ 0(SI),AX
MULQ 8(CX)
MOVQ AX,R10
MOVQ DX,R11
MOVQ 0(SI),AX
MULQ 16(CX)
MOVQ AX,R12
MOVQ DX,R13
MOVQ 0(SI),AX
MULQ 24(CX)
MOVQ AX,R14
MOVQ DX,R15
MOVQ 0(SI),AX
MULQ 32(CX)
MOVQ AX,BX
MOVQ DX,BP
MOVQ 8(SI),AX
MULQ 0(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 8(SI),AX
MULQ 8(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 8(SI),AX
MULQ 16(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ 8(SI),AX
MULQ 24(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 8(SI),DX
IMUL3Q $19,DX,AX
MULQ 32(CX)
ADDQ AX,R8
ADCQ DX,R9
MOVQ 16(SI),AX
MULQ 0(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 16(SI),AX
MULQ 8(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ 16(SI),AX
MULQ 16(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 16(SI),DX
IMUL3Q $19,DX,AX
MULQ 24(CX)
ADDQ AX,R8
ADCQ DX,R9
MOVQ 16(SI),DX
IMUL3Q $19,DX,AX
MULQ 32(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 24(SI),AX
MULQ 0(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ 24(SI),AX
MULQ 8(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 0(SP),AX
MULQ 24(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 0(SP),AX
MULQ 32(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 32(SI),AX
MULQ 0(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 8(SP),AX
MULQ 16(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 8(SP),AX
MULQ 24(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 8(SP),AX
MULQ 32(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ $REDMASK51,SI
SHLQ $13,R8,R9
ANDQ SI,R8
SHLQ $13,R10,R11
ANDQ SI,R10
ADDQ R9,R10
SHLQ $13,R12,R13
ANDQ SI,R12
ADDQ R11,R12
SHLQ $13,R14,R15
ANDQ SI,R14
ADDQ R13,R14
SHLQ $13,BX,BP
ANDQ SI,BX
ADDQ R15,BX
IMUL3Q $19,BP,DX
ADDQ DX,R8
MOVQ R8,DX
SHRQ $51,DX
ADDQ R10,DX
MOVQ DX,CX
SHRQ $51,DX
ANDQ SI,R8
ADDQ R12,DX
MOVQ DX,R9
SHRQ $51,DX
ANDQ SI,CX
ADDQ R14,DX
MOVQ DX,AX
SHRQ $51,DX
ANDQ SI,R9
ADDQ BX,DX
MOVQ DX,R10
SHRQ $51,DX
ANDQ SI,AX
IMUL3Q $19,DX,DX
ADDQ DX,R8
ANDQ SI,R10
MOVQ R8,0(DI)
MOVQ CX,8(DI)
MOVQ R9,16(DI)
MOVQ AX,24(DI)
MOVQ R10,32(DI)
RET
// func square(out, in *[5]uint64)
TEXT ·square(SB),7,$0-16
MOVQ out+0(FP), DI
MOVQ in+8(FP), SI
MOVQ 0(SI),AX
MULQ 0(SI)
MOVQ AX,CX
MOVQ DX,R8
MOVQ 0(SI),AX
SHLQ $1,AX
MULQ 8(SI)
MOVQ AX,R9
MOVQ DX,R10
MOVQ 0(SI),AX
SHLQ $1,AX
MULQ 16(SI)
MOVQ AX,R11
MOVQ DX,R12
MOVQ 0(SI),AX
SHLQ $1,AX
MULQ 24(SI)
MOVQ AX,R13
MOVQ DX,R14
MOVQ 0(SI),AX
SHLQ $1,AX
MULQ 32(SI)
MOVQ AX,R15
MOVQ DX,BX
MOVQ 8(SI),AX
MULQ 8(SI)
ADDQ AX,R11
ADCQ DX,R12
MOVQ 8(SI),AX
SHLQ $1,AX
MULQ 16(SI)
ADDQ AX,R13
ADCQ DX,R14
MOVQ 8(SI),AX
SHLQ $1,AX
MULQ 24(SI)
ADDQ AX,R15
ADCQ DX,BX
MOVQ 8(SI),DX
IMUL3Q $38,DX,AX
MULQ 32(SI)
ADDQ AX,CX
ADCQ DX,R8
MOVQ 16(SI),AX
MULQ 16(SI)
ADDQ AX,R15
ADCQ DX,BX
MOVQ 16(SI),DX
IMUL3Q $38,DX,AX
MULQ 24(SI)
ADDQ AX,CX
ADCQ DX,R8
MOVQ 16(SI),DX
IMUL3Q $38,DX,AX
MULQ 32(SI)
ADDQ AX,R9
ADCQ DX,R10
MOVQ 24(SI),DX
IMUL3Q $19,DX,AX
MULQ 24(SI)
ADDQ AX,R9
ADCQ DX,R10
MOVQ 24(SI),DX
IMUL3Q $38,DX,AX
MULQ 32(SI)
ADDQ AX,R11
ADCQ DX,R12
MOVQ 32(SI),DX
IMUL3Q $19,DX,AX
MULQ 32(SI)
ADDQ AX,R13
ADCQ DX,R14
MOVQ $REDMASK51,SI
SHLQ $13,CX,R8
ANDQ SI,CX
SHLQ $13,R9,R10
ANDQ SI,R9
ADDQ R8,R9
SHLQ $13,R11,R12
ANDQ SI,R11
ADDQ R10,R11
SHLQ $13,R13,R14
ANDQ SI,R13
ADDQ R12,R13
SHLQ $13,R15,BX
ANDQ SI,R15
ADDQ R14,R15
IMUL3Q $19,BX,DX
ADDQ DX,CX
MOVQ CX,DX
SHRQ $51,DX
ADDQ R9,DX
ANDQ SI,CX
MOVQ DX,R8
SHRQ $51,DX
ADDQ R11,DX
ANDQ SI,R8
MOVQ DX,R9
SHRQ $51,DX
ADDQ R13,DX
ANDQ SI,R9
MOVQ DX,AX
SHRQ $51,DX
ADDQ R15,DX
ANDQ SI,AX
MOVQ DX,R10
SHRQ $51,DX
IMUL3Q $19,DX,DX
ADDQ DX,CX
ANDQ SI,R10
MOVQ CX,0(DI)
MOVQ R8,8(DI)
MOVQ R9,16(DI)
MOVQ AX,24(DI)
MOVQ R10,32(DI)
RET
@@ -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 amd64,!gccgo,!appengine,!purego
// +build amd64,!gccgo,!appengine
package curve25519
+169
View File
@@ -0,0 +1,169 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func mul(dest, a, b *[5]uint64)
TEXT ·mul(SB),0,$16-24
MOVQ dest+0(FP), DI
MOVQ a+8(FP), SI
MOVQ b+16(FP), DX
MOVQ DX,CX
MOVQ 24(SI),DX
IMUL3Q $19,DX,AX
MOVQ AX,0(SP)
MULQ 16(CX)
MOVQ AX,R8
MOVQ DX,R9
MOVQ 32(SI),DX
IMUL3Q $19,DX,AX
MOVQ AX,8(SP)
MULQ 8(CX)
ADDQ AX,R8
ADCQ DX,R9
MOVQ 0(SI),AX
MULQ 0(CX)
ADDQ AX,R8
ADCQ DX,R9
MOVQ 0(SI),AX
MULQ 8(CX)
MOVQ AX,R10
MOVQ DX,R11
MOVQ 0(SI),AX
MULQ 16(CX)
MOVQ AX,R12
MOVQ DX,R13
MOVQ 0(SI),AX
MULQ 24(CX)
MOVQ AX,R14
MOVQ DX,R15
MOVQ 0(SI),AX
MULQ 32(CX)
MOVQ AX,BX
MOVQ DX,BP
MOVQ 8(SI),AX
MULQ 0(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 8(SI),AX
MULQ 8(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 8(SI),AX
MULQ 16(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ 8(SI),AX
MULQ 24(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 8(SI),DX
IMUL3Q $19,DX,AX
MULQ 32(CX)
ADDQ AX,R8
ADCQ DX,R9
MOVQ 16(SI),AX
MULQ 0(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 16(SI),AX
MULQ 8(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ 16(SI),AX
MULQ 16(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 16(SI),DX
IMUL3Q $19,DX,AX
MULQ 24(CX)
ADDQ AX,R8
ADCQ DX,R9
MOVQ 16(SI),DX
IMUL3Q $19,DX,AX
MULQ 32(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 24(SI),AX
MULQ 0(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ 24(SI),AX
MULQ 8(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 0(SP),AX
MULQ 24(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 0(SP),AX
MULQ 32(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 32(SI),AX
MULQ 0(CX)
ADDQ AX,BX
ADCQ DX,BP
MOVQ 8(SP),AX
MULQ 16(CX)
ADDQ AX,R10
ADCQ DX,R11
MOVQ 8(SP),AX
MULQ 24(CX)
ADDQ AX,R12
ADCQ DX,R13
MOVQ 8(SP),AX
MULQ 32(CX)
ADDQ AX,R14
ADCQ DX,R15
MOVQ $REDMASK51,SI
SHLQ $13,R8,R9
ANDQ SI,R8
SHLQ $13,R10,R11
ANDQ SI,R10
ADDQ R9,R10
SHLQ $13,R12,R13
ANDQ SI,R12
ADDQ R11,R12
SHLQ $13,R14,R15
ANDQ SI,R14
ADDQ R13,R14
SHLQ $13,BX,BP
ANDQ SI,BX
ADDQ R15,BX
IMUL3Q $19,BP,DX
ADDQ DX,R8
MOVQ R8,DX
SHRQ $51,DX
ADDQ R10,DX
MOVQ DX,CX
SHRQ $51,DX
ANDQ SI,R8
ADDQ R12,DX
MOVQ DX,R9
SHRQ $51,DX
ANDQ SI,CX
ADDQ R14,DX
MOVQ DX,AX
SHRQ $51,DX
ANDQ SI,R9
ADDQ BX,DX
MOVQ DX,R10
SHRQ $51,DX
ANDQ SI,AX
IMUL3Q $19,DX,DX
ADDQ DX,R8
ANDQ SI,R10
MOVQ R8,0(DI)
MOVQ CX,8(DI)
MOVQ R9,16(DI)
MOVQ AX,24(DI)
MOVQ R10,32(DI)
RET
+132
View File
@@ -0,0 +1,132 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
// +build amd64,!gccgo,!appengine
#include "const_amd64.h"
// func square(out, in *[5]uint64)
TEXT ·square(SB),7,$0-16
MOVQ out+0(FP), DI
MOVQ in+8(FP), SI
MOVQ 0(SI),AX
MULQ 0(SI)
MOVQ AX,CX
MOVQ DX,R8
MOVQ 0(SI),AX
SHLQ $1,AX
MULQ 8(SI)
MOVQ AX,R9
MOVQ DX,R10
MOVQ 0(SI),AX
SHLQ $1,AX
MULQ 16(SI)
MOVQ AX,R11
MOVQ DX,R12
MOVQ 0(SI),AX
SHLQ $1,AX
MULQ 24(SI)
MOVQ AX,R13
MOVQ DX,R14
MOVQ 0(SI),AX
SHLQ $1,AX
MULQ 32(SI)
MOVQ AX,R15
MOVQ DX,BX
MOVQ 8(SI),AX
MULQ 8(SI)
ADDQ AX,R11
ADCQ DX,R12
MOVQ 8(SI),AX
SHLQ $1,AX
MULQ 16(SI)
ADDQ AX,R13
ADCQ DX,R14
MOVQ 8(SI),AX
SHLQ $1,AX
MULQ 24(SI)
ADDQ AX,R15
ADCQ DX,BX
MOVQ 8(SI),DX
IMUL3Q $38,DX,AX
MULQ 32(SI)
ADDQ AX,CX
ADCQ DX,R8
MOVQ 16(SI),AX
MULQ 16(SI)
ADDQ AX,R15
ADCQ DX,BX
MOVQ 16(SI),DX
IMUL3Q $38,DX,AX
MULQ 24(SI)
ADDQ AX,CX
ADCQ DX,R8
MOVQ 16(SI),DX
IMUL3Q $38,DX,AX
MULQ 32(SI)
ADDQ AX,R9
ADCQ DX,R10
MOVQ 24(SI),DX
IMUL3Q $19,DX,AX
MULQ 24(SI)
ADDQ AX,R9
ADCQ DX,R10
MOVQ 24(SI),DX
IMUL3Q $38,DX,AX
MULQ 32(SI)
ADDQ AX,R11
ADCQ DX,R12
MOVQ 32(SI),DX
IMUL3Q $19,DX,AX
MULQ 32(SI)
ADDQ AX,R13
ADCQ DX,R14
MOVQ $REDMASK51,SI
SHLQ $13,CX,R8
ANDQ SI,CX
SHLQ $13,R9,R10
ANDQ SI,R9
ADDQ R8,R9
SHLQ $13,R11,R12
ANDQ SI,R11
ADDQ R10,R11
SHLQ $13,R13,R14
ANDQ SI,R13
ADDQ R12,R13
SHLQ $13,R15,BX
ANDQ SI,R15
ADDQ R14,R15
IMUL3Q $19,BX,DX
ADDQ DX,CX
MOVQ CX,DX
SHRQ $51,DX
ADDQ R9,DX
ANDQ SI,CX
MOVQ DX,R8
SHRQ $51,DX
ADDQ R11,DX
ANDQ SI,R8
MOVQ DX,R9
SHRQ $51,DX
ADDQ R13,DX
ANDQ SI,R9
MOVQ DX,AX
SHRQ $51,DX
ADDQ R15,DX
ANDQ SI,AX
MOVQ DX,R10
SHRQ $51,DX
IMUL3Q $19,DX,DX
ADDQ DX,CX
ANDQ SI,R10
MOVQ CX,0(DI)
MOVQ R8,8(DI)
MOVQ R9,16(DI)
MOVQ AX,24(DI)
MOVQ R10,32(DI)
RET
@@ -4,18 +4,6 @@
package curve25519
// lowOrderPoints from libsodium.
// https://github.com/jedisct1/libsodium/blob/65621a1059a37d/src/libsodium/crypto_scalarmult/curve25519/ref10/x25519_ref10.c#L11-L70
var lowOrderPoints = [][]byte{
{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},
{0x01, 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},
{0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae, 0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a, 0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd, 0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00},
{0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57},
{0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
{0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
{0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f},
}
// testVectors generated with BoringSSL.
var testVectors = []struct {
In [32]byte
-5
View File
@@ -2,11 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// In Go 1.13, the ed25519 package was promoted to the standard library as
// crypto/ed25519, and this package became a wrapper for the standard library one.
//
// +build !go1.13
// Package ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/.
//
-73
View File
@@ -1,73 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.13
// Package ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
//
// Beginning with Go 1.13, the functionality of this package was moved to the
// standard library as crypto/ed25519. This package only acts as a compatibility
// wrapper.
package ed25519
import (
"crypto/ed25519"
"io"
)
const (
// PublicKeySize is the size, in bytes, of public keys as used in this package.
PublicKeySize = 32
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
SeedSize = 32
)
// PublicKey is the type of Ed25519 public keys.
//
// This type is an alias for crypto/ed25519's PublicKey type.
// See the crypto/ed25519 package for the methods on this type.
type PublicKey = ed25519.PublicKey
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
//
// This type is an alias for crypto/ed25519's PrivateKey type.
// See the crypto/ed25519 package for the methods on this type.
type PrivateKey = ed25519.PrivateKey
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
return ed25519.GenerateKey(rand)
}
// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
return ed25519.NewKeyFromSeed(seed)
}
// Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte {
return ed25519.Sign(privateKey, message)
}
// Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool {
return ed25519.Verify(publicKey, message, sig)
}
+23 -24
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ed25519_test
package ed25519
import (
"bufio"
@@ -15,7 +15,6 @@ import (
"strings"
"testing"
"golang.org/x/crypto/ed25519"
"golang.org/x/crypto/ed25519/internal/edwards25519"
)
@@ -29,7 +28,7 @@ func (zeroReader) Read(buf []byte) (int, error) {
}
func TestUnmarshalMarshal(t *testing.T) {
pub, _, _ := ed25519.GenerateKey(rand.Reader)
pub, _, _ := GenerateKey(rand.Reader)
var A edwards25519.ExtendedGroupElement
var pubBytes [32]byte
@@ -48,28 +47,28 @@ func TestUnmarshalMarshal(t *testing.T) {
func TestSignVerify(t *testing.T) {
var zero zeroReader
public, private, _ := ed25519.GenerateKey(zero)
public, private, _ := GenerateKey(zero)
message := []byte("test message")
sig := ed25519.Sign(private, message)
if !ed25519.Verify(public, message, sig) {
sig := Sign(private, message)
if !Verify(public, message, sig) {
t.Errorf("valid signature rejected")
}
wrongMessage := []byte("wrong message")
if ed25519.Verify(public, wrongMessage, sig) {
if Verify(public, wrongMessage, sig) {
t.Errorf("signature of different message accepted")
}
}
func TestCryptoSigner(t *testing.T) {
var zero zeroReader
public, private, _ := ed25519.GenerateKey(zero)
public, private, _ := GenerateKey(zero)
signer := crypto.Signer(private)
publicInterface := signer.Public()
public2, ok := publicInterface.(ed25519.PublicKey)
public2, ok := publicInterface.(PublicKey)
if !ok {
t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
}
@@ -85,7 +84,7 @@ func TestCryptoSigner(t *testing.T) {
t.Fatalf("error from Sign(): %s", err)
}
if !ed25519.Verify(public, message, signature) {
if !Verify(public, message, signature) {
t.Errorf("Verify failed on signature from Sign()")
}
}
@@ -122,31 +121,31 @@ func TestGolden(t *testing.T) {
sig, _ := hex.DecodeString(parts[3])
// The signatures in the test vectors also include the message
// at the end, but we just want R and S.
sig = sig[:ed25519.SignatureSize]
sig = sig[:SignatureSize]
if l := len(pubKey); l != ed25519.PublicKeySize {
if l := len(pubKey); l != PublicKeySize {
t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
}
var priv [ed25519.PrivateKeySize]byte
var priv [PrivateKeySize]byte
copy(priv[:], privBytes)
copy(priv[32:], pubKey)
sig2 := ed25519.Sign(priv[:], msg)
sig2 := Sign(priv[:], msg)
if !bytes.Equal(sig, sig2[:]) {
t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
}
if !ed25519.Verify(pubKey, msg, sig2) {
if !Verify(pubKey, msg, sig2) {
t.Errorf("signature failed to verify on line %d", lineNo)
}
priv2 := ed25519.NewKeyFromSeed(priv[:32])
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().(ed25519.PublicKey); !bytes.Equal(pubKey, pubKey2) {
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)
}
@@ -179,7 +178,7 @@ func TestMalleability(t *testing.T) {
0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
}
if ed25519.Verify(publicKey, msg, sig) {
if Verify(publicKey, msg, sig) {
t.Fatal("non-canonical signature accepted")
}
}
@@ -187,7 +186,7 @@ func TestMalleability(t *testing.T) {
func BenchmarkKeyGeneration(b *testing.B) {
var zero zeroReader
for i := 0; i < b.N; i++ {
if _, _, err := ed25519.GenerateKey(zero); err != nil {
if _, _, err := GenerateKey(zero); err != nil {
b.Fatal(err)
}
}
@@ -195,27 +194,27 @@ func BenchmarkKeyGeneration(b *testing.B) {
func BenchmarkSigning(b *testing.B) {
var zero zeroReader
_, priv, err := ed25519.GenerateKey(zero)
_, priv, err := GenerateKey(zero)
if err != nil {
b.Fatal(err)
}
message := []byte("Hello, world!")
b.ResetTimer()
for i := 0; i < b.N; i++ {
ed25519.Sign(priv, message)
Sign(priv, message)
}
}
func BenchmarkVerification(b *testing.B) {
var zero zeroReader
pub, priv, err := ed25519.GenerateKey(zero)
pub, priv, err := GenerateKey(zero)
if err != nil {
b.Fatal(err)
}
message := []byte("Hello, world!")
signature := ed25519.Sign(priv, message)
signature := Sign(priv, message)
b.ResetTimer()
for i := 0; i < b.N; i++ {
ed25519.Verify(pub, message, signature)
Verify(pub, message, signature)
}
}
-24
View File
@@ -1,24 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.13
package ed25519_test
import (
ed25519std "crypto/ed25519"
"golang.org/x/crypto/ed25519"
"testing"
)
func TestTypeAlias(t *testing.T) {
var zero zeroReader
public, private, _ := ed25519std.GenerateKey(zero)
message := []byte("test message")
sig := ed25519.Sign(private, message)
if !ed25519.Verify(public, message, sig) {
t.Errorf("valid signature rejected")
}
}
-2
View File
@@ -1,7 +1,5 @@
module golang.org/x/crypto
go 1.11
require (
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3
golang.org/x/sys v0.0.0-20190412213103-97732733099d
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11,!gccgo,!purego
// +build go1.11
// +build !gccgo,!appengine
#include "textflag.h"
+668
View File
@@ -0,0 +1,668 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Based on CRYPTOGAMS code with the following comment:
// # ====================================================================
// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
// # project. The module is, however, dual licensed under OpenSSL and
// # CRYPTOGAMS licenses depending on where you obtain it. For further
// # details see http://www.openssl.org/~appro/cryptogams/.
// # ====================================================================
// Original code can be found at the link below:
// https://github.com/dot-asm/cryptogams/commit/a60f5b50ed908e91e5c39ca79126a4a876d5d8ff
// There are some differences between CRYPTOGAMS code and this one. The round
// loop for "_int" isn't the same as the original. Some adjustments were
// necessary because there are less vector registers available. For example, some
// X variables (r12, r13, r14, and r15) share the same register used by the
// counter. The original code uses ctr to name the counter. Here we use CNT
// because golang uses CTR as the counter register name.
// +build ppc64le,!gccgo,!appengine
#include "textflag.h"
#define OUT R3
#define INP R4
#define LEN R5
#define KEY R6
#define CNT R7
#define TEMP R8
#define X0 R11
#define X1 R12
#define X2 R14
#define X3 R15
#define X4 R16
#define X5 R17
#define X6 R18
#define X7 R19
#define X8 R20
#define X9 R21
#define X10 R22
#define X11 R23
#define X12 R24
#define X13 R25
#define X14 R26
#define X15 R27
#define CON0 X0
#define CON1 X1
#define CON2 X2
#define CON3 X3
#define KEY0 X4
#define KEY1 X5
#define KEY2 X6
#define KEY3 X7
#define KEY4 X8
#define KEY5 X9
#define KEY6 X10
#define KEY7 X11
#define CNT0 X12
#define CNT1 X13
#define CNT2 X14
#define CNT3 X15
#define TMP0 R9
#define TMP1 R10
#define TMP2 R28
#define TMP3 R29
#define CONSTS R8
#define A0 V0
#define B0 V1
#define C0 V2
#define D0 V3
#define A1 V4
#define B1 V5
#define C1 V6
#define D1 V7
#define A2 V8
#define B2 V9
#define C2 V10
#define D2 V11
#define T0 V12
#define T1 V13
#define T2 V14
#define K0 V15
#define K1 V16
#define K2 V17
#define K3 V18
#define K4 V19
#define K5 V20
#define FOUR V21
#define SIXTEEN V22
#define TWENTY4 V23
#define TWENTY V24
#define TWELVE V25
#define TWENTY5 V26
#define SEVEN V27
#define INPPERM V28
#define OUTPERM V29
#define OUTMASK V30
#define DD0 V31
#define DD1 SEVEN
#define DD2 T0
#define DD3 T1
#define DD4 T2
DATA ·consts+0x00(SB)/8, $0x3320646e61707865
DATA ·consts+0x08(SB)/8, $0x6b20657479622d32
DATA ·consts+0x10(SB)/8, $0x0000000000000001
DATA ·consts+0x18(SB)/8, $0x0000000000000000
DATA ·consts+0x20(SB)/8, $0x0000000000000004
DATA ·consts+0x28(SB)/8, $0x0000000000000000
DATA ·consts+0x30(SB)/8, $0x0a0b08090e0f0c0d
DATA ·consts+0x38(SB)/8, $0x0203000106070405
DATA ·consts+0x40(SB)/8, $0x090a0b080d0e0f0c
DATA ·consts+0x48(SB)/8, $0x0102030005060704
GLOBL ·consts(SB), RODATA, $80
//func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[32]byte, counter *[16]byte)
TEXT ·chaCha20_ctr32_vmx(SB),NOSPLIT|NOFRAME,$0
// Load the arguments inside the registers
MOVD out+0(FP), OUT
MOVD inp+8(FP), INP
MOVD len+16(FP), LEN
MOVD key+24(FP), KEY
MOVD counter+32(FP), CNT
MOVD $·consts(SB), CONSTS // point to consts addr
MOVD $16, X0
MOVD $32, X1
MOVD $48, X2
MOVD $64, X3
MOVD $31, X4
MOVD $15, X5
// Load key
LVX (KEY)(R0), K1
LVSR (KEY)(R0), T0
LVX (KEY)(X0), K2
LVX (KEY)(X4), DD0
// Load counter
LVX (CNT)(R0), K3
LVSR (CNT)(R0), T1
LVX (CNT)(X5), DD1
// Load constants
LVX (CONSTS)(R0), K0
LVX (CONSTS)(X0), K5
LVX (CONSTS)(X1), FOUR
LVX (CONSTS)(X2), SIXTEEN
LVX (CONSTS)(X3), TWENTY4
// Align key and counter
VPERM K2, K1, T0, K1
VPERM DD0, K2, T0, K2
VPERM DD1, K3, T1, K3
// Load counter to GPR
MOVWZ 0(CNT), CNT0
MOVWZ 4(CNT), CNT1
MOVWZ 8(CNT), CNT2
MOVWZ 12(CNT), CNT3
// Adjust vectors for the initial state
VADDUWM K3, K5, K3
VADDUWM K3, K5, K4
VADDUWM K4, K5, K5
// Synthesized constants
VSPLTISW $-12, TWENTY
VSPLTISW $12, TWELVE
VSPLTISW $-7, TWENTY5
VXOR T0, T0, T0
VSPLTISW $-1, OUTMASK
LVSR (INP)(R0), INPPERM
LVSL (OUT)(R0), OUTPERM
VPERM OUTMASK, T0, OUTPERM, OUTMASK
loop_outer_vmx:
// Load constant
MOVD $0x61707865, CON0
MOVD $0x3320646e, CON1
MOVD $0x79622d32, CON2
MOVD $0x6b206574, CON3
VOR K0, K0, A0
VOR K0, K0, A1
VOR K0, K0, A2
VOR K1, K1, B0
MOVD $10, TEMP
// Load key to GPR
MOVWZ 0(KEY), X4
MOVWZ 4(KEY), X5
MOVWZ 8(KEY), X6
MOVWZ 12(KEY), X7
VOR K1, K1, B1
VOR K1, K1, B2
MOVWZ 16(KEY), X8
MOVWZ 0(CNT), X12
MOVWZ 20(KEY), X9
MOVWZ 4(CNT), X13
VOR K2, K2, C0
VOR K2, K2, C1
MOVWZ 24(KEY), X10
MOVWZ 8(CNT), X14
VOR K2, K2, C2
VOR K3, K3, D0
MOVWZ 28(KEY), X11
MOVWZ 12(CNT), X15
VOR K4, K4, D1
VOR K5, K5, D2
MOVD X4, TMP0
MOVD X5, TMP1
MOVD X6, TMP2
MOVD X7, TMP3
VSPLTISW $7, SEVEN
MOVD TEMP, CTR
loop_vmx:
// CRYPTOGAMS uses a macro to create a loop using perl. This isn't possible
// using assembly macros. Therefore, the macro expansion result was used
// in order to maintain the algorithm efficiency.
// This loop generates three keystream blocks using VMX instructions and,
// in parallel, one keystream block using scalar instructions.
ADD X4, X0, X0
ADD X5, X1, X1
VADDUWM A0, B0, A0
VADDUWM A1, B1, A1
ADD X6, X2, X2
ADD X7, X3, X3
VADDUWM A2, B2, A2
VXOR D0, A0, D0
XOR X0, X12, X12
XOR X1, X13, X13
VXOR D1, A1, D1
VXOR D2, A2, D2
XOR X2, X14, X14
XOR X3, X15, X15
VPERM D0, D0, SIXTEEN, D0
VPERM D1, D1, SIXTEEN, D1
ROTLW $16, X12, X12
ROTLW $16, X13, X13
VPERM D2, D2, SIXTEEN, D2
VADDUWM C0, D0, C0
ROTLW $16, X14, X14
ROTLW $16, X15, X15
VADDUWM C1, D1, C1
VADDUWM C2, D2, C2
ADD X12, X8, X8
ADD X13, X9, X9
VXOR B0, C0, T0
VXOR B1, C1, T1
ADD X14, X10, X10
ADD X15, X11, X11
VXOR B2, C2, T2
VRLW T0, TWELVE, B0
XOR X8, X4, X4
XOR X9, X5, X5
VRLW T1, TWELVE, B1
VRLW T2, TWELVE, B2
XOR X10, X6, X6
XOR X11, X7, X7
VADDUWM A0, B0, A0
VADDUWM A1, B1, A1
ROTLW $12, X4, X4
ROTLW $12, X5, X5
VADDUWM A2, B2, A2
VXOR D0, A0, D0
ROTLW $12, X6, X6
ROTLW $12, X7, X7
VXOR D1, A1, D1
VXOR D2, A2, D2
ADD X4, X0, X0
ADD X5, X1, X1
VPERM D0, D0, TWENTY4, D0
VPERM D1, D1, TWENTY4, D1
ADD X6, X2, X2
ADD X7, X3, X3
VPERM D2, D2, TWENTY4, D2
VADDUWM C0, D0, C0
XOR X0, X12, X12
XOR X1, X13, X13
VADDUWM C1, D1, C1
VADDUWM C2, D2, C2
XOR X2, X14, X14
XOR X3, X15, X15
VXOR B0, C0, T0
VXOR B1, C1, T1
ROTLW $8, X12, X12
ROTLW $8, X13, X13
VXOR B2, C2, T2
VRLW T0, SEVEN, B0
ROTLW $8, X14, X14
ROTLW $8, X15, X15
VRLW T1, SEVEN, B1
VRLW T2, SEVEN, B2
ADD X12, X8, X8
ADD X13, X9, X9
VSLDOI $8, C0, C0, C0
VSLDOI $8, C1, C1, C1
ADD X14, X10, X10
ADD X15, X11, X11
VSLDOI $8, C2, C2, C2
VSLDOI $12, B0, B0, B0
XOR X8, X4, X4
XOR X9, X5, X5
VSLDOI $12, B1, B1, B1
VSLDOI $12, B2, B2, B2
XOR X10, X6, X6
XOR X11, X7, X7
VSLDOI $4, D0, D0, D0
VSLDOI $4, D1, D1, D1
ROTLW $7, X4, X4
ROTLW $7, X5, X5
VSLDOI $4, D2, D2, D2
VADDUWM A0, B0, A0
ROTLW $7, X6, X6
ROTLW $7, X7, X7
VADDUWM A1, B1, A1
VADDUWM A2, B2, A2
ADD X5, X0, X0
ADD X6, X1, X1
VXOR D0, A0, D0
VXOR D1, A1, D1
ADD X7, X2, X2
ADD X4, X3, X3
VXOR D2, A2, D2
VPERM D0, D0, SIXTEEN, D0
XOR X0, X15, X15
XOR X1, X12, X12
VPERM D1, D1, SIXTEEN, D1
VPERM D2, D2, SIXTEEN, D2
XOR X2, X13, X13
XOR X3, X14, X14
VADDUWM C0, D0, C0
VADDUWM C1, D1, C1
ROTLW $16, X15, X15
ROTLW $16, X12, X12
VADDUWM C2, D2, C2
VXOR B0, C0, T0
ROTLW $16, X13, X13
ROTLW $16, X14, X14
VXOR B1, C1, T1
VXOR B2, C2, T2
ADD X15, X10, X10
ADD X12, X11, X11
VRLW T0, TWELVE, B0
VRLW T1, TWELVE, B1
ADD X13, X8, X8
ADD X14, X9, X9
VRLW T2, TWELVE, B2
VADDUWM A0, B0, A0
XOR X10, X5, X5
XOR X11, X6, X6
VADDUWM A1, B1, A1
VADDUWM A2, B2, A2
XOR X8, X7, X7
XOR X9, X4, X4
VXOR D0, A0, D0
VXOR D1, A1, D1
ROTLW $12, X5, X5
ROTLW $12, X6, X6
VXOR D2, A2, D2
VPERM D0, D0, TWENTY4, D0
ROTLW $12, X7, X7
ROTLW $12, X4, X4
VPERM D1, D1, TWENTY4, D1
VPERM D2, D2, TWENTY4, D2
ADD X5, X0, X0
ADD X6, X1, X1
VADDUWM C0, D0, C0
VADDUWM C1, D1, C1
ADD X7, X2, X2
ADD X4, X3, X3
VADDUWM C2, D2, C2
VXOR B0, C0, T0
XOR X0, X15, X15
XOR X1, X12, X12
VXOR B1, C1, T1
VXOR B2, C2, T2
XOR X2, X13, X13
XOR X3, X14, X14
VRLW T0, SEVEN, B0
VRLW T1, SEVEN, B1
ROTLW $8, X15, X15
ROTLW $8, X12, X12
VRLW T2, SEVEN, B2
VSLDOI $8, C0, C0, C0
ROTLW $8, X13, X13
ROTLW $8, X14, X14
VSLDOI $8, C1, C1, C1
VSLDOI $8, C2, C2, C2
ADD X15, X10, X10
ADD X12, X11, X11
VSLDOI $4, B0, B0, B0
VSLDOI $4, B1, B1, B1
ADD X13, X8, X8
ADD X14, X9, X9
VSLDOI $4, B2, B2, B2
VSLDOI $12, D0, D0, D0
XOR X10, X5, X5
XOR X11, X6, X6
VSLDOI $12, D1, D1, D1
VSLDOI $12, D2, D2, D2
XOR X8, X7, X7
XOR X9, X4, X4
ROTLW $7, X5, X5
ROTLW $7, X6, X6
ROTLW $7, X7, X7
ROTLW $7, X4, X4
BC 0x10, 0, loop_vmx
SUB $256, LEN, LEN
// Accumulate key block
ADD $0x61707865, X0, X0
ADD $0x3320646e, X1, X1
ADD $0x79622d32, X2, X2
ADD $0x6b206574, X3, X3
ADD TMP0, X4, X4
ADD TMP1, X5, X5
ADD TMP2, X6, X6
ADD TMP3, X7, X7
MOVWZ 16(KEY), TMP0
MOVWZ 20(KEY), TMP1
MOVWZ 24(KEY), TMP2
MOVWZ 28(KEY), TMP3
ADD TMP0, X8, X8
ADD TMP1, X9, X9
ADD TMP2, X10, X10
ADD TMP3, X11, X11
MOVWZ 12(CNT), TMP0
MOVWZ 8(CNT), TMP1
MOVWZ 4(CNT), TMP2
MOVWZ 0(CNT), TEMP
ADD TMP0, X15, X15
ADD TMP1, X14, X14
ADD TMP2, X13, X13
ADD TEMP, X12, X12
// Accumulate key block
VADDUWM A0, K0, A0
VADDUWM A1, K0, A1
VADDUWM A2, K0, A2
VADDUWM B0, K1, B0
VADDUWM B1, K1, B1
VADDUWM B2, K1, B2
VADDUWM C0, K2, C0
VADDUWM C1, K2, C1
VADDUWM C2, K2, C2
VADDUWM D0, K3, D0
VADDUWM D1, K4, D1
VADDUWM D2, K5, D2
// Increment counter
ADD $4, TEMP, TEMP
MOVW TEMP, 0(CNT)
VADDUWM K3, FOUR, K3
VADDUWM K4, FOUR, K4
VADDUWM K5, FOUR, K5
// XOR the input slice (INP) with the keystream, which is stored in GPRs (X0-X3).
// Load input (aligned or not)
MOVWZ 0(INP), TMP0
MOVWZ 4(INP), TMP1
MOVWZ 8(INP), TMP2
MOVWZ 12(INP), TMP3
// XOR with input
XOR TMP0, X0, X0
XOR TMP1, X1, X1
XOR TMP2, X2, X2
XOR TMP3, X3, X3
MOVWZ 16(INP), TMP0
MOVWZ 20(INP), TMP1
MOVWZ 24(INP), TMP2
MOVWZ 28(INP), TMP3
XOR TMP0, X4, X4
XOR TMP1, X5, X5
XOR TMP2, X6, X6
XOR TMP3, X7, X7
MOVWZ 32(INP), TMP0
MOVWZ 36(INP), TMP1
MOVWZ 40(INP), TMP2
MOVWZ 44(INP), TMP3
XOR TMP0, X8, X8
XOR TMP1, X9, X9
XOR TMP2, X10, X10
XOR TMP3, X11, X11
MOVWZ 48(INP), TMP0
MOVWZ 52(INP), TMP1
MOVWZ 56(INP), TMP2
MOVWZ 60(INP), TMP3
XOR TMP0, X12, X12
XOR TMP1, X13, X13
XOR TMP2, X14, X14
XOR TMP3, X15, X15
// Store output (aligned or not)
MOVW X0, 0(OUT)
MOVW X1, 4(OUT)
MOVW X2, 8(OUT)
MOVW X3, 12(OUT)
ADD $64, INP, INP // INP points to the end of the slice for the alignment code below
MOVW X4, 16(OUT)
MOVD $16, TMP0
MOVW X5, 20(OUT)
MOVD $32, TMP1
MOVW X6, 24(OUT)
MOVD $48, TMP2
MOVW X7, 28(OUT)
MOVD $64, TMP3
MOVW X8, 32(OUT)
MOVW X9, 36(OUT)
MOVW X10, 40(OUT)
MOVW X11, 44(OUT)
MOVW X12, 48(OUT)
MOVW X13, 52(OUT)
MOVW X14, 56(OUT)
MOVW X15, 60(OUT)
ADD $64, OUT, OUT
// Load input
LVX (INP)(R0), DD0
LVX (INP)(TMP0), DD1
LVX (INP)(TMP1), DD2
LVX (INP)(TMP2), DD3
LVX (INP)(TMP3), DD4
ADD $64, INP, INP
VPERM DD1, DD0, INPPERM, DD0 // Align input
VPERM DD2, DD1, INPPERM, DD1
VPERM DD3, DD2, INPPERM, DD2
VPERM DD4, DD3, INPPERM, DD3
VXOR A0, DD0, A0 // XOR with input
VXOR B0, DD1, B0
LVX (INP)(TMP0), DD1 // Keep loading input
VXOR C0, DD2, C0
LVX (INP)(TMP1), DD2
VXOR D0, DD3, D0
LVX (INP)(TMP2), DD3
LVX (INP)(TMP3), DD0
ADD $64, INP, INP
MOVD $63, TMP3 // 63 is not a typo
VPERM A0, A0, OUTPERM, A0
VPERM B0, B0, OUTPERM, B0
VPERM C0, C0, OUTPERM, C0
VPERM D0, D0, OUTPERM, D0
VPERM DD1, DD4, INPPERM, DD4 // Align input
VPERM DD2, DD1, INPPERM, DD1
VPERM DD3, DD2, INPPERM, DD2
VPERM DD0, DD3, INPPERM, DD3
VXOR A1, DD4, A1
VXOR B1, DD1, B1
LVX (INP)(TMP0), DD1 // Keep loading
VXOR C1, DD2, C1
LVX (INP)(TMP1), DD2
VXOR D1, DD3, D1
LVX (INP)(TMP2), DD3
// Note that the LVX address is always rounded down to the nearest 16-byte
// boundary, and that it always points to at most 15 bytes beyond the end of
// the slice, so we cannot cross a page boundary.
LVX (INP)(TMP3), DD4 // Redundant in aligned case.
ADD $64, INP, INP
VPERM A1, A1, OUTPERM, A1 // Pre-misalign output
VPERM B1, B1, OUTPERM, B1
VPERM C1, C1, OUTPERM, C1
VPERM D1, D1, OUTPERM, D1
VPERM DD1, DD0, INPPERM, DD0 // Align Input
VPERM DD2, DD1, INPPERM, DD1
VPERM DD3, DD2, INPPERM, DD2
VPERM DD4, DD3, INPPERM, DD3
VXOR A2, DD0, A2
VXOR B2, DD1, B2
VXOR C2, DD2, C2
VXOR D2, DD3, D2
VPERM A2, A2, OUTPERM, A2
VPERM B2, B2, OUTPERM, B2
VPERM C2, C2, OUTPERM, C2
VPERM D2, D2, OUTPERM, D2
ANDCC $15, OUT, X1 // Is out aligned?
MOVD OUT, X0
VSEL A0, B0, OUTMASK, DD0 // Collect pre-misaligned output
VSEL B0, C0, OUTMASK, DD1
VSEL C0, D0, OUTMASK, DD2
VSEL D0, A1, OUTMASK, DD3
VSEL A1, B1, OUTMASK, B0
VSEL B1, C1, OUTMASK, C0
VSEL C1, D1, OUTMASK, D0
VSEL D1, A2, OUTMASK, A1
VSEL A2, B2, OUTMASK, B1
VSEL B2, C2, OUTMASK, C1
VSEL C2, D2, OUTMASK, D1
STVX DD0, (OUT+TMP0)
STVX DD1, (OUT+TMP1)
STVX DD2, (OUT+TMP2)
ADD $64, OUT, OUT
STVX DD3, (OUT+R0)
STVX B0, (OUT+TMP0)
STVX C0, (OUT+TMP1)
STVX D0, (OUT+TMP2)
ADD $64, OUT, OUT
STVX A1, (OUT+R0)
STVX B1, (OUT+TMP0)
STVX C1, (OUT+TMP1)
STVX D1, (OUT+TMP2)
ADD $64, OUT, OUT
BEQ aligned_vmx
SUB X1, OUT, X2 // in misaligned case edges
MOVD $0, X3 // are written byte-by-byte
unaligned_tail_vmx:
STVEBX D2, (X2+X3)
ADD $1, X3, X3
CMPW X3, X1
BNE unaligned_tail_vmx
SUB X1, X0, X2
unaligned_head_vmx:
STVEBX A0, (X2+X1)
CMPW X1, $15
ADD $1, X1, X1
BNE unaligned_head_vmx
CMPU LEN, $255 // done with 256-byte block yet?
BGT loop_outer_vmx
JMP done_vmx
aligned_vmx:
STVX A0, (X0+R0)
CMPU LEN, $255 // done with 256-byte block yet?
BGT loop_outer_vmx
done_vmx:
RET
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.11
// +build !gccgo
package chacha20
const (
haveAsm = true
bufSize = 256
)
//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
if len(src) >= bufSize {
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
}
if len(src)%bufSize != 0 {
i := len(src) - len(src)%bufSize
c.buf = [bufSize]byte{}
copy(c.buf[:], src[i:])
xorKeyStreamVX(c.buf[:], c.buf[:], &c.key, &c.nonce, &c.counter)
c.len = bufSize - copy(dst[i:], c.buf[:len(src)%bufSize])
}
}
+264
View File
@@ -0,0 +1,264 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package ChaCha20 implements the core ChaCha20 function as specified
// in https://tools.ietf.org/html/rfc7539#section-2.3.
package chacha20
import (
"crypto/cipher"
"encoding/binary"
"golang.org/x/crypto/internal/subtle"
)
// assert that *Cipher implements cipher.Stream
var _ cipher.Stream = (*Cipher)(nil)
// Cipher is a stateful instance of ChaCha20 using a particular key
// and nonce. A *Cipher implements the cipher.Stream interface.
type Cipher struct {
key [8]uint32
counter uint32 // incremented after each block
nonce [3]uint32
buf [bufSize]byte // buffer for unused keystream bytes
len int // number of unused keystream bytes at end of buf
}
// New creates a new ChaCha20 stream cipher with the given key and nonce.
// The initial counter value is set to 0.
func New(key [8]uint32, nonce [3]uint32) *Cipher {
return &Cipher{key: key, nonce: nonce}
}
// ChaCha20 constants spelling "expand 32-byte k"
const (
j0 uint32 = 0x61707865
j1 uint32 = 0x3320646e
j2 uint32 = 0x79622d32
j3 uint32 = 0x6b206574
)
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
a += b
d ^= a
d = (d << 16) | (d >> 16)
c += d
b ^= c
b = (b << 12) | (b >> 20)
a += b
d ^= a
d = (d << 8) | (d >> 24)
c += d
b ^= c
b = (b << 7) | (b >> 25)
return a, b, c, d
}
// XORKeyStream XORs each byte in the given slice with a byte from the
// cipher's key stream. Dst and src must overlap entirely or not at all.
//
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
// to pass a dst bigger than src, and in that case, XORKeyStream will
// only update dst[:len(src)] and will not touch the rest of dst.
//
// Multiple calls to XORKeyStream behave as if the concatenation of
// the src buffers was passed in a single run. That is, Cipher
// maintains state and does not reset at each XORKeyStream call.
func (s *Cipher) XORKeyStream(dst, src []byte) {
if len(dst) < len(src) {
panic("chacha20: output smaller than input")
}
if subtle.InexactOverlap(dst[:len(src)], src) {
panic("chacha20: invalid buffer overlap")
}
// xor src with buffered keystream first
if s.len != 0 {
buf := s.buf[len(s.buf)-s.len:]
if len(src) < len(buf) {
buf = buf[:len(src)]
}
td, ts := dst[:len(buf)], src[:len(buf)] // BCE hint
for i, b := range buf {
td[i] = ts[i] ^ b
}
s.len -= len(buf)
if s.len != 0 {
return
}
s.buf = [len(s.buf)]byte{} // zero the empty buffer
src = src[len(buf):]
dst = dst[len(buf):]
}
if len(src) == 0 {
return
}
if haveAsm {
if uint64(len(src))+uint64(s.counter)*64 > (1<<38)-64 {
panic("chacha20: counter overflow")
}
s.xorKeyStreamAsm(dst, src)
return
}
// set up a 64-byte buffer to pad out the final block if needed
// (hoisted out of the main loop to avoid spills)
rem := len(src) % 64 // length of final block
fin := len(src) - rem // index of final block
if rem > 0 {
copy(s.buf[len(s.buf)-64:], src[fin:])
}
// pre-calculate most of the first round
s1, s5, s9, s13 := quarterRound(j1, s.key[1], s.key[5], s.nonce[0])
s2, s6, s10, s14 := quarterRound(j2, s.key[2], s.key[6], s.nonce[1])
s3, s7, s11, s15 := quarterRound(j3, s.key[3], s.key[7], s.nonce[2])
n := len(src)
src, dst = src[:n:n], dst[:n:n] // BCE hint
for i := 0; i < n; i += 64 {
// calculate the remainder of the first round
s0, s4, s8, s12 := quarterRound(j0, s.key[0], s.key[4], s.counter)
// execute the second round
x0, x5, x10, x15 := quarterRound(s0, s5, s10, s15)
x1, x6, x11, x12 := quarterRound(s1, s6, s11, s12)
x2, x7, x8, x13 := quarterRound(s2, s7, s8, s13)
x3, x4, x9, x14 := quarterRound(s3, s4, s9, s14)
// execute the remaining 18 rounds
for i := 0; i < 9; i++ {
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
}
x0 += j0
x1 += j1
x2 += j2
x3 += j3
x4 += s.key[0]
x5 += s.key[1]
x6 += s.key[2]
x7 += s.key[3]
x8 += s.key[4]
x9 += s.key[5]
x10 += s.key[6]
x11 += s.key[7]
x12 += s.counter
x13 += s.nonce[0]
x14 += s.nonce[1]
x15 += s.nonce[2]
// increment the counter
s.counter += 1
if s.counter == 0 {
panic("chacha20: counter overflow")
}
// pad to 64 bytes if needed
in, out := src[i:], dst[i:]
if i == fin {
// src[fin:] has already been copied into s.buf before
// the main loop
in, out = s.buf[len(s.buf)-64:], s.buf[len(s.buf)-64:]
}
in, out = in[:64], out[:64] // BCE hint
// XOR the key stream with the source and write out the result
xor(out[0:], in[0:], x0)
xor(out[4:], in[4:], x1)
xor(out[8:], in[8:], x2)
xor(out[12:], in[12:], x3)
xor(out[16:], in[16:], x4)
xor(out[20:], in[20:], x5)
xor(out[24:], in[24:], x6)
xor(out[28:], in[28:], x7)
xor(out[32:], in[32:], x8)
xor(out[36:], in[36:], x9)
xor(out[40:], in[40:], x10)
xor(out[44:], in[44:], x11)
xor(out[48:], in[48:], x12)
xor(out[52:], in[52:], x13)
xor(out[56:], in[56:], x14)
xor(out[60:], in[60:], x15)
}
// copy any trailing bytes out of the buffer and into dst
if rem != 0 {
s.len = 64 - rem
copy(dst[fin:], s.buf[len(s.buf)-64:])
}
}
// Advance discards bytes in the key stream until the next 64 byte block
// boundary is reached and updates the counter accordingly. If the key
// stream is already at a block boundary no bytes will be discarded and
// the counter will be unchanged.
func (s *Cipher) Advance() {
s.len -= s.len % 64
if s.len == 0 {
s.buf = [len(s.buf)]byte{}
}
}
// XORKeyStream crypts bytes from in to out using the given key and counters.
// In and out must overlap entirely or not at all. Counter contains the raw
// ChaCha20 counter bytes (i.e. block counter followed by nonce).
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
s := Cipher{
key: [8]uint32{
binary.LittleEndian.Uint32(key[0:4]),
binary.LittleEndian.Uint32(key[4:8]),
binary.LittleEndian.Uint32(key[8:12]),
binary.LittleEndian.Uint32(key[12:16]),
binary.LittleEndian.Uint32(key[16:20]),
binary.LittleEndian.Uint32(key[20:24]),
binary.LittleEndian.Uint32(key[24:28]),
binary.LittleEndian.Uint32(key[28:32]),
},
nonce: [3]uint32{
binary.LittleEndian.Uint32(counter[4:8]),
binary.LittleEndian.Uint32(counter[8:12]),
binary.LittleEndian.Uint32(counter[12:16]),
},
counter: binary.LittleEndian.Uint32(counter[0:4]),
}
s.XORKeyStream(out, in)
}
// HChaCha20 uses the ChaCha20 core to generate a derived key from a key and a
// nonce. It should only be used as part of the XChaCha20 construction.
func HChaCha20(key *[8]uint32, nonce *[4]uint32) [8]uint32 {
x0, x1, x2, x3 := j0, j1, j2, j3
x4, x5, x6, x7 := key[0], key[1], key[2], key[3]
x8, x9, x10, x11 := key[4], key[5], key[6], key[7]
x12, x13, x14, x15 := nonce[0], nonce[1], nonce[2], nonce[3]
for i := 0; i < 10; i++ {
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
}
var out [8]uint32
out[0], out[1], out[2], out[3] = x0, x1, x2, x3
out[4], out[5], out[6], out[7] = x12, x13, x14, x15
return out
}
@@ -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 !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo purego
// +build !ppc64le,!arm64,!s390x arm64,!go1.11 gccgo appengine
package chacha20
const bufSize = blockSize
const (
bufSize = 64
haveAsm = false
)
func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) {
s.xorKeyStreamBlocksGeneric(dst, src)
func (*Cipher) xorKeyStreamAsm(dst, src []byte) {
panic("not implemented")
}
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ppc64le,!gccgo,!appengine
package chacha20
import "encoding/binary"
const (
bufSize = 256
haveAsm = true
)
//go:noescape
func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
if len(src) >= bufSize {
chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter)
}
if len(src)%bufSize != 0 {
chaCha20_ctr32_vmx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
start := len(src) - len(src)%bufSize
ts, td, tb := src[start:], dst[start:], c.buf[:]
// Unroll loop to XOR 32 bytes per iteration.
for i := 0; i < len(ts)-32; i += 32 {
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
s0 := binary.LittleEndian.Uint64(ts[0:8])
s1 := binary.LittleEndian.Uint64(ts[8:16])
s2 := binary.LittleEndian.Uint64(ts[16:24])
s3 := binary.LittleEndian.Uint64(ts[24:32])
b0 := binary.LittleEndian.Uint64(tb[0:8])
b1 := binary.LittleEndian.Uint64(tb[8:16])
b2 := binary.LittleEndian.Uint64(tb[16:24])
b3 := binary.LittleEndian.Uint64(tb[24:32])
binary.LittleEndian.PutUint64(td[0:8], s0^b0)
binary.LittleEndian.PutUint64(td[8:16], s1^b1)
binary.LittleEndian.PutUint64(td[16:24], s2^b2)
binary.LittleEndian.PutUint64(td[24:32], s3^b3)
ts, td, tb = ts[32:], td[32:], tb[32:]
}
td, tb = td[:len(ts)], tb[:len(ts)] // bounds check elimination
for i, v := range ts {
td[i] = tb[i] ^ v
}
c.len = bufSize - (len(src) % bufSize)
}
}
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build s390x,!gccgo,!appengine
package chacha20
import (
"golang.org/x/sys/cpu"
)
var haveAsm = cpu.S390X.HasVX
const bufSize = 256
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
// be called when the vector facility is available.
// Implementation in asm_s390x.s.
//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32, buf *[256]byte, len *int)
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter, &c.buf, &c.len)
}
// EXRL targets, DO NOT CALL!
func mvcSrcToBuf()
func mvcBufToDst()
@@ -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 !gccgo,!purego
// +build s390x,!gccgo,!appengine
#include "go_asm.h"
#include "textflag.h"
@@ -24,6 +24,15 @@ 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
@@ -135,7 +144,7 @@ DATA ·constants<>+0x1c(SB)/4, $0x6b206574
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)
// 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]
@@ -143,10 +152,25 @@ TEXT ·xorKeyStreamVX(SB), NOSPLIT, $0
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
@@ -193,7 +217,9 @@ 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)
@@ -219,6 +245,16 @@ loop:
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
+225
View File
@@ -0,0 +1,225 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package chacha20
import (
"encoding/binary"
"encoding/hex"
"fmt"
"math/rand"
"testing"
)
func TestCore(t *testing.T) {
// This is just a smoke test that checks the example from
// https://tools.ietf.org/html/rfc7539#section-2.3.2. The
// chacha20poly1305 package contains much more extensive tests of this
// code.
var key [32]byte
for i := range key {
key[i] = byte(i)
}
var input [16]byte
input[0] = 1
input[7] = 9
input[11] = 0x4a
var out [64]byte
XORKeyStream(out[:], out[:], &input, &key)
const expected = "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
if result := hex.EncodeToString(out[:]); result != expected {
t.Errorf("wanted %x but got %x", expected, result)
}
}
// 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)
}
}
}
@@ -7,504 +7,571 @@ package chacha20
// Test vectors for ChaCha20 implementations.
type testCase struct {
nonce string
key string
length int
nonce [3]uint32
key [8]uint32
input string
output string
}
var testVectors = [...]testCase{
{
// From libsodium/test/default/xchacha20.c
nonce: "c047548266b7c370d33566a2425cbf30d82d1eaf5294109e",
key: "9d23bd4149cb979ccf3c5c94dd217e9808cb0e50cd0f67812235eaaf601d6232",
input: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
output: "a21209096594de8c5667b1d13ad93f744106d054df210e4782cd396fec692d3515a20bf351eec011a92c367888bc464c32f0807acd6c203a247e0db854148468e9f96bee4cf718d68d5f637cbd5a376457788e6fae90fc31097cfc",
},
{
// From draft-irtf-cfrg-xchacha-01
nonce: "404142434445464748494a4b4c4d4e4f5051525354555658",
key: "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
input: "5468652064686f6c65202870726f6e6f756e6365642022646f6c65222920697320616c736f206b6e6f776e2061732074686520417369617469632077696c6420646f672c2072656420646f672c20616e642077686973746c696e6720646f672e2049742069732061626f7574207468652073697a65206f662061204765726d616e20736865706865726420627574206c6f6f6b73206d6f7265206c696b652061206c6f6e672d6c656767656420666f782e205468697320686967686c7920656c757369766520616e6420736b696c6c6564206a756d70657220697320636c6173736966696564207769746820776f6c7665732c20636f796f7465732c206a61636b616c732c20616e6420666f78657320696e20746865207461786f6e6f6d69632066616d696c792043616e696461652e",
output: "4559abba4e48c16102e8bb2c05e6947f50a786de162f9b0b7e592a9b53d0d4e98d8d6410d540a1a6375b26d80dace4fab52384c731acbf16a5923c0c48d3575d4d0d2c673b666faa731061277701093a6bf7a158a8864292a41c48e3a9b4c0daece0f8d98d0d7e05b37a307bbb66333164ec9e1b24ea0d6c3ffddcec4f68e7443056193a03c810e11344ca06d8ed8a2bfb1e8d48cfa6bc0eb4e2464b748142407c9f431aee769960e15ba8b96890466ef2457599852385c661f752ce20f9da0c09ab6b19df74e76a95967446f8d0fd415e7bee2a12a114c20eb5292ae7a349ae577820d5520a1f3fb62a17ce6a7e68fa7c79111d8860920bc048ef43fe84486ccb87c25f0ae045f0cce1e7989a9aa220a28bdd4827e751a24a6d5c62d790a66393b93111c1a55dd7421a10184974c7c5",
},
{
nonce: "1733d194b3a2b6063600fe3f",
key: "b6a3a89de64abf3aae9cf1a207c768101e80e472925d16ce8f02e761573dac82",
length: 0,
nonce: [3]uint32{0x94d13317, 0x6b6a2b3, 0x3ffe0036},
key: [8]uint32{0x9da8a3b6, 0x3abf4ae6, 0xa2f19cae, 0x1068c707, 0x72e4801e, 0xce165d92, 0x61e7028f, 0x82ac3d57},
input: "",
output: "",
},
{
nonce: "ddfa69041ecc3feeb077cf45",
key: "2be077349f80bf45faa1f427e81d90dbdc90a1d8d4212c1dacf2bd870000bfdf",
length: 5,
nonce: [3]uint32{0x469fadd, 0xee3fcc1e, 0x45cf77b0},
key: [8]uint32{0x3477e02b, 0x45bf809f, 0x27f4a1fa, 0xdb901de8, 0xd8a190dc, 0x1d2c21d4, 0x87bdf2ac, 0xdfbf0000},
input: "23dbad0780",
output: "415a3e498d",
},
{
nonce: "496b2a516daff98da5a23653",
key: "254c12e973a3d14fbbf7457964f0d5ee5d18c42913cf9a3c67a3944c532c2c7c",
length: 9,
nonce: [3]uint32{0x512a6b49, 0x8df9af6d, 0x5336a2a5},
key: [8]uint32{0xe9124c25, 0x4fd1a373, 0x7945f7bb, 0xeed5f064, 0x29c4185d, 0x3c9acf13, 0x4c94a367, 0x7c2c2c53},
input: "f518831fab69c054a6",
output: "cfe40f63f81391484b",
},
{
nonce: "9e7a69ca17672f6b209285b7",
key: "205082fc0b41a45cd085527d9d1c0a16410b47152a743436faa74ae67ae60bca",
length: 12,
nonce: [3]uint32{0xca697a9e, 0x6b2f6717, 0xb7859220},
key: [8]uint32{0xfc825020, 0x5ca4410b, 0x7d5285d0, 0x160a1c9d, 0x15470b41, 0x3634742a, 0xe64aa7fa, 0xca0be67a},
input: "805fad1d62951537aeed9859",
output: "47bd303f93c3ce04bce44710",
},
{
nonce: "b33dedcd7f0a77359bdeae06",
key: "ef2d6344a720e4a58f2ac10f159ab76314e37d3316bf2fb857bc043127927c67",
length: 14,
nonce: [3]uint32{0xcded3db3, 0x35770a7f, 0x6aede9b},
key: [8]uint32{0x44632def, 0xa5e420a7, 0xfc12a8f, 0x63b79a15, 0x337de314, 0xb82fbf16, 0x3104bc57, 0x677c9227},
input: "f4e8a7577affb841cf48392cf5df",
output: "f445c0fb7e3d5bfdab47090ddee6",
},
{
nonce: "b1508a348092cc4ace14608d",
key: "a831bd347ef40828f9198b9d8396f54d48435831454aa734a274e10ddcc7d429",
length: 15,
nonce: [3]uint32{0x348a50b1, 0x4acc9280, 0x8d6014ce},
key: [8]uint32{0x34bd31a8, 0x2808f47e, 0x9d8b19f9, 0x4df59683, 0x31584348, 0x34a74a45, 0xde174a2, 0x29d4c7dc},
input: "1179b71ec4dc34bd812f742b5a0b27",
output: "cc7f80f333c647d6e592e4f7ecc834",
},
{
nonce: "034775c821c58891a6e88cac",
key: "ed793ce92b1689ce66836a117f65dcec981dc85b522f5dffbb3e1f172f3f7750",
length: 20,
nonce: [3]uint32{0xc8754703, 0x9188c521, 0xac8ce8a6},
key: [8]uint32{0xe93c79ed, 0xce89162b, 0x116a8366, 0xecdc657f, 0x5bc81d98, 0xff5d2f52, 0x171f3ebb, 0x50773f2f},
input: "7bd94943d55392d0311c413ac755ce0347872ba3",
output: "c43665de15136af232675d9d5dbbeca77f3c542a",
},
{
nonce: "cb55869aa56e9d6e5e70ad5d",
key: "b3d542358ffd7b1ff8ab3810ece814729356d0edbd63e66006d5e5e8a223a9ee",
length: 21,
nonce: [3]uint32{0x9a8655cb, 0x6e9d6ea5, 0x5dad705e},
key: [8]uint32{0x3542d5b3, 0x1f7bfd8f, 0x1038abf8, 0x7214e8ec, 0xedd05693, 0x60e663bd, 0xe8e5d506, 0xeea923a2},
input: "1505f669acc5ad9aaa0e993ba8c24e744d13655e1f",
output: "26cad1ccf4cf4c49b267ab7be10bc2ffa3ba66bc86",
},
{
nonce: "a42c203f86fc63000ea16072",
key: "d6b18ae2473d3be8ca711267ffbc77b97644f6a2b4791d31d0910d180c6e1aec",
length: 25,
nonce: [3]uint32{0x3f202ca4, 0x63fc86, 0x7260a10e},
key: [8]uint32{0xe28ab1d6, 0xe83b3d47, 0x671271ca, 0xb977bcff, 0xa2f64476, 0x311d79b4, 0x180d91d0, 0xec1a6e0c},
input: "20070523ddb4ebf0d5f20fd95aacf47fb269ebadda6879638a",
output: "5ce972624cb2b7e7c28f5b865ba08c887911b4f5e361830a4b",
},
{
nonce: "ea7186cf2fdf728d8a535a8b",
key: "bba26ce4efb56ad06b96e2b02d0cdd549ad81588a9306c421e0f5b0175ae4b25",
length: 31,
nonce: [3]uint32{0xcf8671ea, 0x8d72df2f, 0x8b5a538a},
key: [8]uint32{0xe46ca2bb, 0xd06ab5ef, 0xb0e2966b, 0x54dd0c2d, 0x8815d89a, 0x426c30a9, 0x15b0f1e, 0x254bae75},
input: "d10f8050c1186f92e26f351db36490d82ea677498562d8d4f487a0a4058adf",
output: "f30c11bc553b2baf6870760d735680897c9fee168f976b2a33ef395fdbd4fc",
},
{
nonce: "3a98bed189a35a0fe1c726fa",
key: "a76d5c79dcaab18c9a3542a0272eea95c45382122f59bcaa10e8910371d941f6",
length: 34,
nonce: [3]uint32{0xd1be983a, 0xf5aa389, 0xfa26c7e1},
key: [8]uint32{0x795c6da7, 0x8cb1aadc, 0xa042359a, 0x95ea2e27, 0x128253c4, 0xaabc592f, 0x391e810, 0xf641d971},
input: "e88dc380b7d45a4a762c34f310199587867516fac4a2634022b96a9f862e17714d17",
output: "aac98ba3821399e55a5eab5862f7f1bfc63637d700125878c2b17151f306c9aec80e",
},
{
nonce: "b8f4f598731d183f2e57f45b",
key: "f78c6fa82b1ab48d5631e0e0598aad3dbad1e4b338fbf6759d7094dbf334dbc3",
length: 34,
nonce: [3]uint32{0x98f5f4b8, 0x3f181d73, 0x5bf4572e},
key: [8]uint32{0xa86f8cf7, 0x8db41a2b, 0xe0e03156, 0x3dad8a59, 0xb3e4d1ba, 0x75f6fb38, 0xdb94709d, 0xc3db34f3},
input: "b0fcf0a731e2902787309697db2384e1cda07b60002c95355a4e261fb601f034b2b3",
output: "b6c8c40ddda029a70a21c25f724cc90c43f6edc407055683572a9f5e9690a1d571bb",
},
{
nonce: "18ae8972507ebe7e7691817d",
key: "a0076c332ba22e4a462f87a8285e7ba43f5e64be91651c377a23dcd28095c592",
length: 40,
nonce: [3]uint32{0x7289ae18, 0x7ebe7e50, 0x7d819176},
key: [8]uint32{0x336c07a0, 0x4a2ea22b, 0xa8872f46, 0xa47b5e28, 0xbe645e3f, 0x371c6591, 0xd2dc237a, 0x92c59580},
input: "cf9ec6fa3f0a67488adb5598a48ed916729a1e416d206f9675dfa9fd6585793f274f363bbca348b3",
output: "bb7ed8a199aa329dcd18736ce705804ffae8c3e2ba341ae907f94f4672d57175df25d28e16962fd6",
},
{
nonce: "de8131fd263e198b99c7eb0b",
key: "2e4c1a78e255ab2743af4a8101ab0b0ae02ce69dd2032b47e818eedf935b858b",
length: 47,
nonce: [3]uint32{0xfd3181de, 0x8b193e26, 0xbebc799},
key: [8]uint32{0x781a4c2e, 0x27ab55e2, 0x814aaf43, 0xa0bab01, 0x9de62ce0, 0x472b03d2, 0xdfee18e8, 0x8b855b93},
input: "be9a8211d68642310724eda3dd02f63fcc03a101d9564b0ecee6f4ecececcb0099bb26aabee46b1a2c0416b4ac269e",
output: "3152f317cf3626e26d02cff9392619ea02e22115b6d43d6dd2e1177c6bb3cb71c4a90c3d13b63c43e03605ec98d9a1",
},
{
nonce: "f62fb0273e6110a5d8228b21",
key: "3277fc62f46cf0ced55ef4a44f65962f6e952b9ff472b542869cb55b4f78e435",
length: 51,
nonce: [3]uint32{0x27b02ff6, 0xa510613e, 0x218b22d8},
key: [8]uint32{0x62fc7732, 0xcef06cf4, 0xa4f45ed5, 0x2f96654f, 0x9f2b956e, 0x42b572f4, 0x5bb59c86, 0x35e4784f},
input: "495343a257250f8970f791f493b89d10edba89806b88aaaeb3b5aefd078ba7b765746164bce653f5e6c096dd8499fb76d97d77",
output: "62c01f426581551b5b16e8b1a3a23c86bcdd189ab695dbea4bf811a14741e6ebbb0261ef8ae47778a6be7e0ef11697b891412c",
},
{
nonce: "637ab99d4802f50f56dfb6f2",
key: "8f7a652b5d5767fe61d256aa979a1730f1fffcae98b68e9b5637fe1e0c45eab4",
length: 52,
nonce: [3]uint32{0x9db97a63, 0xff50248, 0xf2b6df56},
key: [8]uint32{0x2b657a8f, 0xfe67575d, 0xaa56d261, 0x30179a97, 0xaefcfff1, 0x9b8eb698, 0x1efe3756, 0xb4ea450c},
input: "e37fbbd3fe37ce5a99d18e5dcb0dafe7adf8b596528708f7d310569ab44c251377f7363a390c653965e0cb8dd217464b3d8f79c1",
output: "b07d4c56fb83a49e8d9fc992e1230bb5086fecbd828cdbc7353f61b1a3cec0baf9c5bf67c9da06b49469a999ba3b37916ec125be",
},
{
nonce: "38ecdfc1d303757d663c3e9a",
key: "e7d8148613049bdefab4482a44e7bdcb5edc5dad3ed8449117d6d97445db0b23",
length: 56,
nonce: [3]uint32{0xc1dfec38, 0x7d7503d3, 0x9a3e3c66},
key: [8]uint32{0x8614d8e7, 0xde9b0413, 0x2a48b4fa, 0xcbbde744, 0xad5ddc5e, 0x9144d83e, 0x74d9d617, 0x230bdb45},
input: "9efab614388a7d99102bcc901e3623d31fd9dd9d3c3338d086f69c13e7aa8653f9ce76e722e5a6a8cbbbee067a6cb9c59aa9b4b4c518bbed",
output: "829d9fe74b7a4b3aeb04580b41d38a156ffbebba5d49ad55d1b0370f25abcd41221304941ad8e0d5095e15fbd839295bf1e7a509a807c005",
},
{
nonce: "1c52e2c7b4995479d76c94c7",
key: "74e7fc53bf534b9a3441615f1494c3a3727ca0a81123249399ecae435aeb6d21",
length: 63,
nonce: [3]uint32{0xc7e2521c, 0x795499b4, 0xc7946cd7},
key: [8]uint32{0x53fce774, 0x9a4b53bf, 0x5f614134, 0xa3c39414, 0xa8a07c72, 0x93242311, 0x43aeec99, 0x216deb5a},
input: "03b5d7ab4bd8c9a4f47ec122cbeb595bd1a0d58de3bb3dcc66c4e288f29622d6863e846fdfb27a90740feb03a4761c6017250bc0f129cc65d19680ab9d6970",
output: "83db55d9eb441a909268311da67d432c732ad6bda0a0dae710d1bce040b91269deb558a68ced4aa5760ca0b9c5efc84e725f297bdbdadbc368bea4e20261c5",
},
{
nonce: "a1f0411d78773b7ca5ee9169",
key: "393e211f141d26562c7cfc15c5ccfe21c58456a9060560266bc0dcdab010c8f2",
length: 66,
nonce: [3]uint32{0x1d41f0a1, 0x7c3b7778, 0x6991eea5},
key: [8]uint32{0x1f213e39, 0x56261d14, 0x15fc7c2c, 0x21feccc5, 0xa95684c5, 0x26600506, 0xdadcc06b, 0xf2c810b0},
input: "2f4da518578a2a82c8c855155645838ca431cdf35d9f8562f256746150580ca1c74f79b3e9ae78224573da8b47a4b3cc63fbed8d4e831a6b4d796c124d87c78a66e5",
output: "6fc086ded3d1d5566577ccd9971e713c1126ec52d3894f09ab701116c7b5abda959cbb207f4468eb7b6a6b7e1b6d2bc6047f337499d63522f256ee751b91f84f70b6",
},
{
nonce: "2c029f74b0da21a052228c64",
key: "b0e7aca1a10e7a56b913af52080ca3cb746d7ae039ca3b5c07acb285c0afb503",
length: 72,
nonce: [3]uint32{0x749f022c, 0xa021dab0, 0x648c2252},
key: [8]uint32{0xa1ace7b0, 0x567a0ea1, 0x52af13b9, 0xcba30c08, 0xe07a6d74, 0x5c3bca39, 0x85b2ac07, 0x3b5afc0},
input: "55739a1738b4a4028021b21549e2661b050e3d830ad9a56f57bfcaca3e0f72051b9ca92411840061083e5e45124d8425061ab26c632ac7852118411ac80026da946357c630f27225",
output: "8051bf98f8f2617e159ba205a9342ab700973dd045e09321805eed89e419f37f3211c5aa82666b9a097270babc26d3bfe0c990fe245ae982a31f23cfbf6156b5c8cfb77f340e2bf5",
},
{
nonce: "a86bc1234ecdd19fcb4e22cb",
key: "4a4094b698f1b586ff1bfd10544ea81309e521ab64d74374f1b33109f2876e68",
length: 74,
nonce: [3]uint32{0x23c16ba8, 0x9fd1cd4e, 0xcb224ecb},
key: [8]uint32{0xb694404a, 0x86b5f198, 0x10fd1bff, 0x13a84e54, 0xab21e509, 0x7443d764, 0x931b3f1, 0x686e87f2},
input: "7ffd8d5970fdee613eeae531d1c673fd379d64b0b6bfedd010433b080b561038f7f266fa7e15d7d8e10d23f21b9d7724bb200b0f58b9250483e784f4a6555d09c234e8d1c549ebb76a8e",
output: "c173617e36ea20ce04c490803b2098bd4f1ff4b31fdca1c51c6475ade83892c5f12731652d5774631d55ae2938617a5e9462bb6083328a23a4fba52de50ca9075586f2efc22aae56e3a8",
},
{
nonce: "296f5fd61962f7f39e3c039a",
key: "c417a0eb1a42e06917239e44118a85293a52c8d0a2c9b0a884cab20a451a01af",
length: 81,
nonce: [3]uint32{0xd65f6f29, 0xf3f76219, 0x9a033c9e},
key: [8]uint32{0xeba017c4, 0x69e0421a, 0x449e2317, 0x29858a11, 0xd0c8523a, 0xa8b0c9a2, 0xab2ca84, 0xaf011a45},
input: "7a5766097562361cfaeac5b8a6175e1ceeeda30aec5e354df4302e7700ea48c505da9fdc57874da879480ecfea9c6c8904f330cbac5e27f296b33b667fea483348f031bef761d0b8e318a8132caa7a5943",
output: "5e9fbf427c4f0fcf44db3180ea47d923f52bee933a985543622eff70e2b3f5c673be8e05cd7acbcadd8593da454c60d5f19131e61730a73b9c0f87e3921ee5a591a086446b2a0fadd8a4bc7b49a8e83764",
},
{
nonce: "6ee50ec741ec580e616fd9af",
key: "bbf22a177cd285904dc4a28cda48a18ab0880c29397418888147d518ce2c3f63",
length: 88,
nonce: [3]uint32{0xc70ee56e, 0xe58ec41, 0xafd96f61},
key: [8]uint32{0x172af2bb, 0x9085d27c, 0x8ca2c44d, 0x8aa148da, 0x290c88b0, 0x88187439, 0x18d54781, 0x633f2cce},
input: "0777c02a2900052d9b79f38387d2c234108a2ad066cbf7df6ea6acc5a3f86b3d6156abb5b18ad4ecf79e171383a1897e64a95ecdbba6aa3f1c7c12fe31283629ff547cb113a826cb348a7c10507cc645fa2eb97b5f22e44d",
output: "368c90db3464ba488340b1960e9f75d2c3b5b392bdd5622ff70e85e6d00b1e6a996ba3978ce64f8f2b5a9a90576c8f32b908233e15d2f443cccc98af87745c93c8056603407a3fb37ce0c1f8ab6384cc37c69c98bfecf337",
},
{
nonce: "79da06301d054827dc7cc172",
key: "e8b7cd6028e9cbceb97a9be13715d63099c1fba0bf387789a90577dd63175c3e",
length: 92,
nonce: [3]uint32{0x3006da79, 0x2748051d, 0x72c17cdc},
key: [8]uint32{0x60cdb7e8, 0xcecbe928, 0xe19b7ab9, 0x30d61537, 0xa0fbc199, 0x897738bf, 0xdd7705a9, 0x3e5c1763},
input: "cf2dccbcfd781c030376f9019d841ca701cb54a1791f50f50bee0c2bf178182603a4712b5916eebd5001595c3f48283f1ba097ce2e7bf94f2b7fa957ce776e14a7a570093be2de386ececbd6525e72c5970c3e7d35974b8f0b831fbc",
output: "7c92b8c75e6eb8675229660cedcb10334965a7737cde7336512d9eff846c670d1fa8f8a427ea4f43e66be609466711fd241ccff7d3f049bda3a2394e5aa2108abc80e859611dbd3c7ba2d044a3ececa4980dd65e823dd110fea7a548",
},
{
nonce: "eeb10ffc0ac64c4167bd4441",
key: "c6913210b6032b8248b59ad2fe3e8fc86a0536691fa6aa285878dfa01935a2da",
length: 96,
nonce: [3]uint32{0xfc0fb1ee, 0x414cc60a, 0x4144bd67},
key: [8]uint32{0x103291c6, 0x822b03b6, 0xd29ab548, 0xc88f3efe, 0x6936056a, 0x28aaa61f, 0xa0df7858, 0xdaa23519},
input: "e08a8949a1bfd6a8c1186b431b6ad59b106ae5552821db69b66dc03fbc4a2b970dcf9c7da4f5082572bc978f8ee27c554c8884b5a450b36d70453348cd6cac9b80c9900cf98a4088803f564bb1281d24507b2f61ba737c8145c71b50eb0f6dfc",
output: "73d043acf9dcd758c7299bd1fd1f4100d61ff77d339e279bfbe6f9233b0d9afa24992a9c1c7a19545d469fdfb369c201322f6fe8c633fcdcffef31032bfb41b9fb55506e301d049fd447d61f974a713debeaed886f486a98efd3d6c3f25fbb30",
},
{
nonce: "570c03c2e1593b1e1ade7e60",
key: "b5c2bad18345a9569b478b621ea556308f8fbf693de0f12dd2489d4b79c3f57d",
length: 103,
nonce: [3]uint32{0xc2030c57, 0x1e3b59e1, 0x607ede1a},
key: [8]uint32{0xd1bac2b5, 0x56a94583, 0x628b479b, 0x3056a51e, 0x69bf8f8f, 0x2df1e03d, 0x4b9d48d2, 0x7df5c379},
input: "a0c302120111f00c99cff7d839cdf43207a7e2f73d5dd888daa00d84254db0e621a72493480420c9c61ce1cfc54188ff525bb7a0e6c1cd298f598973a1de9fd2d79a21401588775b0adbe261ba4e4f79a894d1bd5835b5924d09ba32ef03cb4bc0bd6eb4ee4274",
output: "bc714bd7d8399beedc238f7ddeb0b99d94ad6bf8bf54548a3e4b90a76aa5673c91db6482591e8ff9126e1412bce56d52a4c2d89f22c29858e24482f177abacef428d0ae1779f0ae0778c44f9f02fe474da93c35c615b5fad29eca697978891f426714441317f2b",
},
{
nonce: "1fc84df4e7036ecf966796f4",
key: "f4127b0d89473f68b48f82c7a0c60f82eb3112c5d71667e493ef36406cb9af26",
length: 109,
nonce: [3]uint32{0xf44dc81f, 0xcf6e03e7, 0xf4966796},
key: [8]uint32{0xd7b12f4, 0x683f4789, 0xc7828fb4, 0x820fc6a0, 0xc51231eb, 0xe46716d7, 0x4036ef93, 0x26afb96c},
input: "ebce290c03c7cb65d053918ba2da0256dc700b337b8c124c43d5da4746888ca78387feea1a3a72c5e249d3d93a1907977dd4009699a15be5da2ca89c60e971c8df5d4553b61b710d92d3453dea595a0e45ae1e093f02ea70608b7b32f9c6aadc661a052f9b14c03ea0117a3192",
output: "cbb8c4ec827a1123c1141327c594d4a8b0b4a74b0008115bb9ec4275db3a8e5529a4f145551af29c473764cbaa0794b2d1eb1066f32a07fd39f5f3fe51498c46fba5310ae7c3664571d6a851e673ded3badc25e426f9c6038724779aa6d2d8ec3f54865f7df612e25575635ab5",
},
{
nonce: "1b463e8d60c3057eddafbb3b",
key: "c917b9f9f79bf89ac9bbec7d7beae5e755ab4a9bbef6ef90906d9ba11a9bf6b9",
length: 115,
nonce: [3]uint32{0x8d3e461b, 0x7e05c360, 0x3bbbafdd},
key: [8]uint32{0xf9b917c9, 0x9af89bf7, 0x7decbbc9, 0xe7e5ea7b, 0x9b4aab55, 0x90eff6be, 0xa19b6d90, 0xb9f69b1a},
input: "275c97de985aa265332065ccce437770b110737a77dea62137a5d6cb62e9cb8b504d34334a58a71aba153d9b86f21377467b2fafaf54829331bf2ce0009acb37842b7a4b5f152aab650a393153f1ed479abc21f7a6fe205b9852ff2f7f3a0e3bfe76ca9770efada4e29e06db0569a99d08648e",
output: "b225aa01d5c438d572deaea51ac12c0c694e0f9dc0ed2884a98e5e2943d52bb4692d7d8f12486de12d0559087e8c09e4f2d5b74e350838aa2bd36023032ccbcae56be75c6a17c59583d81a1fd60e305af5053ac89f753c9347f3040e48405232dc8428c49dcb3d9b899145f5b3bc955f34dbbe",
},
{
nonce: "f5331f87bae3fee4931e8ccb",
key: "03491233e587027e8f98d6e95f406219b5c1215fe695c62ac900b246ba98da9f",
length: 119,
nonce: [3]uint32{0x871f33f5, 0xe4fee3ba, 0xcb8c1e93},
key: [8]uint32{0x33124903, 0x7e0287e5, 0xe9d6988f, 0x1962405f, 0x5f21c1b5, 0x2ac695e6, 0x46b200c9, 0x9fda98ba},
input: "ceda15cfffd53ccebe31b5886facd863f6166e02ec65f46f54148860a5c2702e34fd204d881af6055952690cd1ffa8ba4d0e297cc165d981b371932adb935398c987baff335108c5e77f2e5dd5e1ca9a017bc376cbdbe3c0f45e079c212e8986b438444e79cd37927c1479f45c9e75b0076cc9f8679011",
output: "a3f1c3f885583b999c85cd118e2ababfa5a2de0c8eb28aacc161b1efee89d8de36ddeb584174c0e92011b8d667cb64009049976082072e6262933dbf7b14839805e1face375b7cbb54f9828ba1ed8aa55634ec5d72b6351feff4d77a3a22b34203b02e096f5e5f9ae9ad6a9dd16c57ce6d94dcc8873d18",
},
{
nonce: "e83c55efea20e1df3a7e049a",
key: "c179f4be8b4f555989f097bf1e6f315228e4410104dc26ff578f0ce1598a56a7",
length: 120,
nonce: [3]uint32{0xef553ce8, 0xdfe120ea, 0x9a047e3a},
key: [8]uint32{0xbef479c1, 0x59554f8b, 0xbf97f089, 0x52316f1e, 0x141e428, 0xff26dc04, 0xe10c8f57, 0xa7568a59},
input: "799bb2d634406753416b3a2b67513293a0b3496ef5b2d019758dedaaac2edd72502fc4a375b3f0d4237bc16b0e3d47e7ddc315c6aef3a23fcae2eb3a6083bc7ac4fd1b5bf0025cc1cb266b40234b77db762c747d3a7b27956cf3a4cf72320fb60c0d0713fa60b37a6cb5b21a599e79d0f06a5b7201aeb5d2",
output: "e84dfb3dbaac364085497aeabd197db852d3140c0c07f5f10e5c144c1fe26a50a9877649e88c6fe04283f4b7590a8d0d042ef577693f76f706e31c4979437590fe0ab03d89afb089d1be50ae173ea5458810372838eceac53bf4bac792735d8149e548efb432e236da92bf3168bbcf36f644c23efb478a4e",
},
{
nonce: "a02481d9aa80cd78fc5cc53d",
key: "416e2802e3383ef16b4735f7fc4bc433978797d795459c4a13040806d8fd9912",
length: 123,
nonce: [3]uint32{0xd98124a0, 0x78cd80aa, 0x3dc55cfc},
key: [8]uint32{0x2286e41, 0xf13e38e3, 0xf735476b, 0x33c44bfc, 0xd7978797, 0x4a9c4595, 0x6080413, 0x1299fdd8},
input: "b2d060bd173955f44ee01b8bfcf0a6fad017c3517e4e8c8da728379f6d54471c955615e2b1effe4ce3d0139df225223c361be1cac416ade10a749c5da324563696dae8272577e44e8588cd5306bff0bfbdb32af3ac7cbc78be24b51baf4d5e47cf8f1d6b0a63ed9359da45c3e7297b2314028848f5816feab885e2",
output: "ffa4aa66dd5d39694ae64696bfa96f771accef68f195456ad815751e25c47ed4f27b436f1b3e3fcaa3e0d04133b53559c100cd633ced3d4321fc56225c85d2443727bce40434455aa4c1f3e6768c0fe58ad88b3a928313d41a7629f1ce874d2c8bcf822ebdaebfd9d95a31bb62daab5385eb8eefe026e8cbf1ff7a",
},
{
nonce: "0f6b105381fd11dff3b6d169",
key: "38b1360794e1cd55c173820fe668c2f7d52b366155b43cbbfcc9d344fdd3567d",
length: 127,
nonce: [3]uint32{0x53106b0f, 0xdf11fd81, 0x69d1b6f3},
key: [8]uint32{0x736b138, 0x55cde194, 0xf8273c1, 0xf7c268e6, 0x61362bd5, 0xbb3cb455, 0x44d3c9fc, 0x7d56d3fd},
input: "4f0171d7309493a349530940feece3c6200693f9cff38924114d53f723d090fffa3c80731b5ca989d3e924d1fa14266632cb9ab879e1a36df22dc9f8d1dadea229db72fded0c42187c38b9fa263c20e5fb5b4aa80eb90e8616e36d9b8c613b371c402343823184ecad3532058a46cf9e7ea5a9ecad043ac3028cbcc3f36d32",
output: "88c773ff34b23e691e14018ba1b2bd48a4a6979b377eb0d68336ce6192dcd5177e6b4f1c4bea2df90af56b35fe2a1d6279d253c0194dcbca9bf136f92d69165b216e4c9d1ce6b3fbe40c71e32c3f4088de352732d0e2bad9c16fd0bb9bde3d6c30257ce063432d09f19da79d49aa7641124a6c9e3f09449e911edbae11a053",
},
{
nonce: "bdff905e73f198a8889a9f26",
key: "5fe044529bbeadf9ac549f9e46004623eacd8267962c98ba6b5021c7e3f710ed",
length: 130,
nonce: [3]uint32{0x5e90ffbd, 0xa898f173, 0x269f9a88},
key: [8]uint32{0x5244e05f, 0xf9adbe9b, 0x9e9f54ac, 0x23460046, 0x6782cdea, 0xba982c96, 0xc721506b, 0xed10f7e3},
input: "8f8d9e18d3212bd20b96d75c06d1a63622fd83d13f79d542e45996135368772ea81511302a0d87e246dd346314cfe019bae8a5c97f567f12d82aca98dfea397c6a47dd0c419f1c609d9c52dcfcbe7eee68b2635954206ed592b7081442ce9ce3187d10ccd41cc856fb924b011f817c676c9419f52a2938c7af5f76755a75eb065411",
output: "4e130c5df384b9c3c84aa38a744260735e93783da0337ade99f777e692c5ea276ac4cc65880b4ae9c3b96888760fdddb74bc2e2694bedf1ee6f14619c8015f951ba81b274b466e318d09defe80bdbed57bc213ac4631d2eb14c8e348181d60f6295ceee1e9231ae047830ef4778ff66146621b76974773b5d11c8e17a476450f46ef",
},
{
nonce: "e8398e304ff1a49a96db11f5",
key: "19523b8388e5824b2c652d4bd76e8f7c63e84bfee5503a9d9b0988b868198d9f",
length: 130,
nonce: [3]uint32{0x308e39e8, 0x9aa4f14f, 0xf511db96},
key: [8]uint32{0x833b5219, 0x4b82e588, 0x4b2d652c, 0x7c8f6ed7, 0xfe4be863, 0x9d3a50e5, 0xb888099b, 0x9f8d1968},
input: "30d2379dd3ceae612182576f9acf6de505ab5a9445fe1a86ae75c5c29429e11c50fd9ec657b29b173a3763b1e171b5a7da1803ba5d64fccb2d32cb7788be194dbca00c3c91774c4c4c8ede48c1027d7cc8b387101a4fe5e44a1d9693b2f627626025072806083aadbced91c9711a0171f52ffb8ed5596cf34130022398c8a1da99c7",
output: "b1e8da34ad0189038ee24673979b405ef73fdbdd6f376f800031d64005a4ebed51a37f2180571223848decbea6dd22b198ab9560d7edc047c5d69183dc69b5fca346911d25cb2a1a9f830dc6382ad0024e8c3eef3aa2d155abcfe43bff01956a5e20a862fbed5c5e8df8eed0601a120caac634b068314e221f175baa11ae29002bb9",
},
{
nonce: "5acafea5b4c13a750966a4c5",
key: "5948bfabf69b8d826daaf7f7a28c2025adc0a4d78232dd2fc2b8fc2b4bd88983",
length: 135,
nonce: [3]uint32{0xa5feca5a, 0x753ac1b4, 0xc5a46609},
key: [8]uint32{0xabbf4859, 0x828d9bf6, 0xf7f7aa6d, 0x25208ca2, 0xd7a4c0ad, 0x2fdd3282, 0x2bfcb8c2, 0x8389d84b},
input: "d9404ccdcc8ef128a1b1ace4f9f1669d274ec82aa914cac34b83ac00b236478fd6167e96ec658850c6c139eb0f6fc0dd7191ba9a39828032008f7f37eb9a8df9d6cdd54240e600efe7fc49a674000c5030d825b2c5c96d0f19b8ecdbf4eeb86d3e569c5e3131abc7d6359dd4255284ccacf150d42e7a899536d51ee6db329654a4581c5ac6e419",
output: "c5534b5fb40b4834300e9577a9d87440c5272263d06e6aee84aa92cdf5d1b033145d336f26e5fe55c09a7e75753af93d0786dfc1cb435e86c67bd3ec8e766d0801b99e68691e2c3c3ffec539cf62e68285ea9027daa2716cd6f97e8eb7b9e266357a25eb2d4839a829508a6b7228f2832b3cd998f77597ae530430e6e4ecb53eb9efe456863a04",
},
{
nonce: "4658aa126c4f608885950dc1",
key: "d6cc91149d552f60060c08d4bdfa0202f8f4d3ff174c14bf3c3fbf8875330808",
length: 135,
nonce: [3]uint32{0x12aa5846, 0x88604f6c, 0xc10d9585},
key: [8]uint32{0x1491ccd6, 0x602f559d, 0xd4080c06, 0x202fabd, 0xffd3f4f8, 0xbf144c17, 0x88bf3f3c, 0x8083375},
input: "231765f832927461f338aceb0f4cf51fd8469348c69c549c1dec7333d4aa4968c1ed58b65ab3fe3d0562600a2b076d56fd9ef91f589752e0455dd1d2e614cacfc0d757a11a4a2264bd38f23d3cca108632201b4f6c3b06477467726dde0c2f3aee01d66d788247663f1d0e66b044da9393ede27b9905b44115b067914961bdade85a2eca2844e1",
output: "1dd35f3f774f66d88cb7c2b23820ee078a093d0d85f86c4f103d869f93e2dbdd8a7cb8f101084fe1d7281a71754ec9aac5eb4fca8c365b24ed80e695caace1a8781a5a225938b50b8be96d0499752fdabd4f50d0b6ce396c6e2ca45308d1f2cc5a2a2361a8ca7a334e6ee62d466d74a1b0bf5b352f4ef6d8f8c589b733748bd3d7cda593243fab",
},
{
nonce: "f0709d1c67a388a02b4dc24e",
key: "75974e4952a8070d4af28aaf5c825bc68067e0c5cebafb17b5711d65efd848f5",
length: 140,
nonce: [3]uint32{0x1c9d70f0, 0xa088a367, 0x4ec24d2b},
key: [8]uint32{0x494e9775, 0xd07a852, 0xaf8af24a, 0xc65b825c, 0xc5e06780, 0x17fbbace, 0x651d71b5, 0xf548d8ef},
input: "e46841f12d98aeb7710b9162d342895a971b0e3a499886bbb6aa74dc744a28d89a54542b628acdc2f693cb7c03f73fc3b74069bc3f2d000a145fb8a806cdc7d6fa971da09a33b92851cc3d1f6f5646d7fa2b1d564876feefeb63b6e66dba1c0b86ca345235bb822e0f93132346840d2a3d6eb1b541178ea51affc7b31f8da02732cc4e5bcb5d8683ae0a91c9",
output: "1dcbfd0bb2b905656c52bd7b1bcdad9b4d434ae9ac221a0d3a316115cdd4a463fa9b3444d2612a4e277d0dcd881fa6e80e59e5a54e35e1a14747aed31edf4ac24214f9d9c329ebe2157620b64efaded9976549bc4aa100d5c15be3f85f700f8a21dfe77590dfee2de9a23cc1ed1e44f32ebf68ca289b097bc13b42802dc7c75309c4afc25b5741839f7db3d5",
},
{
nonce: "8b7b06236d6c275b606ccaae",
key: "8844d62973293a89efb4e332d4d5f32a1bc05e094cb605c87d8b4e8862708d79",
length: 144,
nonce: [3]uint32{0x23067b8b, 0x5b276c6d, 0xaeca6c60},
key: [8]uint32{0x29d64488, 0x893a2973, 0x32e3b4ef, 0x2af3d5d4, 0x95ec01b, 0xc805b64c, 0x884e8b7d, 0x798d7062},
input: "e98e4a9550bdd29e4106f0cc8669dcc646a69438408e9a72c7cdb9b9d437b5f7a13fcb197629541c55bca1f8972a80cd1c1f591a0e24f977cdeb84763eab2648e42286e6473ea95e3a6a43b07a32b6a6cd80fe007ba0cf7f5ac7e651431f5e72690ec52a7134f9757daf0d8eff6b831a229db4ab8288f6bbf81e16fedebe621fd1737c8792cfd15fb3040f4f6a4cbc1e",
output: "5c69cf522c058790a3bc38979e172b60e71f7896d362d754edc1668d4f388b3fc0acdf40786d2f34886e107a142b1e724b9b9b171cb0e38fd78b35f8ac5269d74296c39c9f8628d848f57af9d8525a33f19021db2b9c64ba113171ebb3882075019ec7e77b51ce80b063ed41d48dad481d9536c030002a75d15c1c10ce0ec3ff17bc483f8416055a99b53035f4b6ea60",
},
{
nonce: "5896072b85daf5bd0d45758a",
key: "a3eac94919880462a5cfaa9bdcad7038e182c605f3fff9f44b8e84a3c1ebc10a",
length: 148,
nonce: [3]uint32{0x2b079658, 0xbdf5da85, 0x8a75450d},
key: [8]uint32{0x49c9eaa3, 0x62048819, 0x9baacfa5, 0x3870addc, 0x5c682e1, 0xf4f9fff3, 0xa3848e4b, 0xac1ebc1},
input: "ce0f0d900dd0d31749d08631ec59f216a1391f66a73bae81d3b0e2919a461bc9a14d6a01b827e3bcb55bbccf27c1ed574157e6becd5cf47181a73c9d3e865ab48a20551027e560e965876b0e1a256bfa5cb5179bf54bd8ec65e5570e374b853b37bf4b3ef1ec612d288ebc19275fa88da9419e012f957f9b6a7e375b3377db0eb3619c731aebfeb0930772b4020d3a3e90723e72",
output: "b06981b57fe184091ef9f8ccf522a5bcdb59bf9a68a3ddb817fdd999a6ecf81053a602141cf1b17017bae592b6b6e64756631a2b29a9e1b4f877c8b2ae30f71bc921e4f34b6f9cd8e587c57a30245f80e95005d0f18f5114400785140e6743da352d921fb4a74632a9c40115ad7706263ac9b41a11609fa0c42fc00f8d60931976162598df63ebad9496dd8943d25a03fa47475c",
},
{
nonce: "b88a8e097be7d884415830bb",
key: "3cf9b5468d77b2c88f27c52c4c90a3d24f5dce06e859440c305ca30402dcea2f",
length: 148,
nonce: [3]uint32{0x98e8ab8, 0x84d8e77b, 0xbb305841},
key: [8]uint32{0x46b5f93c, 0xc8b2778d, 0x2cc5278f, 0xd2a3904c, 0x6ce5d4f, 0xc4459e8, 0x4a35c30, 0x2feadc02},
input: "eccfd66bdc691478f354b8423d6a3f20932a1f591d8e6cefa734975fb8ee6881b6dc92c0d1d5ed54fd1999efd7f11ac697a1f130587dd895eb498c9a8fc7d1714c385ec156ecae3bdea2a3462834245e724531d0fedda2b77693a53ed7354b758e875b23cfc83219a091fb2076e7a88cd77f779ed96f8d81ffa3fe5059303ac706086494b9f2982f4f88a0c6fadc3748625004db",
output: "925529047d4177b72bf50905ba77e47608815522c1829b24046e439d5451901257903a5409fb910373167e8b7f4fdfa543a477608ddfc11bbd1efc138366961463b9915b302a346b795dd593f6fcf4fa73529b6fe83079552aabbe99474a72806f59688d826675fa7f6649b9f5307e5028853c9821b8c4a1a0fc4bfdc7c8c78b25aeaba2b5821d17b36317381a3bd578917d2504",
},
{
nonce: "4a6e2a2e8a486d9ab66c96f9",
key: "ff3b90583f17bec2b52861e253afb6b6eb8e2f093633cf38fb90df7f374be27a",
length: 152,
nonce: [3]uint32{0x2e2a6e4a, 0x9a6d488a, 0xf9966cb6},
key: [8]uint32{0x58903bff, 0xc2be173f, 0xe26128b5, 0xb6b6af53, 0x92f8eeb, 0x38cf3336, 0x7fdf90fb, 0x7ae24b37},
input: "f0c7139c69413869bca980d7f192b2bc3f57e34ca4f26164e1a54a234e84e1aa285cc02cfbaef3dfba2dbb52a555ec1f6ef0e89d0b2f0bd1846e65b74444b5f003a7308965e67bed558689be2668ca10ca368fac072e0e4535a031af23b3c37c561e185872b86c9bceddb5c1199e43fb5f735384766d33710460b541b52d3f5b6c108c08e76724bcac7ad2d866a8bbeeea92a3d867660d2e",
output: "d2c16c7a242b493038203daec65960de384c030eb698ef6a53c36eabb7556cbfa4770eaa8bc0a2b385ad97495eeb1c03ff4e6efcb804aefa81c177dc62700a9eefe6e8dd10cff5d43a2f47463cab5eb1ee260c3826cac9bfa070f1e0435541a89ebd224d13cc43f8fff12f38091c2b3f2102d5c20d8b1c3ae4f129364bbe9f9ce2147dcf0639668ddb90dffe6a50f939f53fa7ba358e913f",
},
{
nonce: "98013e248c44840860e7319a",
key: "bc17e037902e1e9baa9d6715ee234af9fe6da80d4ca8eec3999719dd92fbef6e",
length: 155,
nonce: [3]uint32{0x243e0198, 0x884448c, 0x9a31e760},
key: [8]uint32{0x37e017bc, 0x9b1e2e90, 0x15679daa, 0xf94a23ee, 0xda86dfe, 0xc3eea84c, 0xdd199799, 0x6eeffb92},
input: "7024974ebf3f66e25631c0699bcc057be0af06bc60d81a7131acaa620a998e15f385c4eaf51ff1e0a81ae5c6a7442d28a3cdc8aeb9701055e75d39ecac35f1e0ac9f9affb6f9197c0066bf39338a2286316e9d1bb7464398e411da1507c470d64f88d11d86d09e6958fa856583ace697f4ee4edc82618662cb3c5380cb4ce7f01c770aab3467d6367c409a83e447c36768a92fc78f9cbe5698c11e",
output: "ff56a3a6e3867588c753260b320c301ce80de8c406545fdd69025abc21ce7430cba6b4f4a08ad3d95dc09be50e67beeff20d1983a98b9cb544b91165f9a0a5b803a66c4e21bd3a10b463b7c1f565e66064f7019362290c77238d72b0ea1e264c0939d76799843439b9f09e220982eb1dc075d449412f838709428a6b8975db25163c58f40bf320514abf7a685150d37a98bac8b34ccb5245edb551",
},
{
nonce: "6d864ed2d8259dc5f123f6fc",
key: "a0cc325fc5ca6741ee4349c0eca17f50c0df8fad2dfa66624153f0223e147480",
length: 160,
nonce: [3]uint32{0xd24e866d, 0xc59d25d8, 0xfcf623f1},
key: [8]uint32{0x5f32cca0, 0x4167cac5, 0xc04943ee, 0x507fa1ec, 0xad8fdfc0, 0x6266fa2d, 0x22f05341, 0x8074143e},
input: "8d79329cf647e966fde65a57fc959223c745801c55312046b791671773cca0af4cd48ead1f316eba0da44aa5d18025eced0c9ed97abaabb24570d89b5b00c179dca15dbae89c0b12bb9e67028e3ae4d6065041b76e508706bec36517a135554d8e6ef7cf3b613cbf894bec65d4dc4e8cb5ca8734ad397238e1e5f528fa11181a57dc71cc3d8c29f3aba45f746b1e8c7faace119c9ba23a05fffd9022c6c85260",
output: "60aea840869f7be6fcc5584b87f43d7ba91ed2d246a8f0a58e82c5153772a9561bdf08e31a0a974f8a057b04a238feb014403cd5ffe9cf231db292199198271f9793c9202387f0835a1e1dc24f85dd86cb34608923783fd38226244a2dd745071b27d49cbffebea80d9dacad1578c09852406aa15250de58d6d09cf50c3fcfff3313fac92c8dad5cb0a61ccc02c91cecee3f628e30c666698edecf81831e55ec",
},
{
nonce: "4710b63001f90c812415684d",
key: "d07614e58d0098df9ee6df596691b30d4a4a1e6c5e1676fb85f1805135fb5973",
length: 167,
nonce: [3]uint32{0x30b61047, 0x810cf901, 0x4d681524},
key: [8]uint32{0xe51476d0, 0xdf98008d, 0x59dfe69e, 0xdb39166, 0x6c1e4a4a, 0xfb76165e, 0x5180f185, 0x7359fb35},
input: "85484293a843d2d80b72924b7972dfa97cbe5b8c6bcc096f4d5b38956eb3f13f47b02b0f759ea37014ecdecfb55f2707ef6d7e81fd4973c92b0043eac160aaf90a4f32b83067b708a08b48db7c5900d87e4f2f62b932cf0981de72b4feea50a5eb00e39429c374698cbe5b86cf3e1fc313a6156a1559f73c5bac146ceaaaf3ccf81917c3fdd0b639d57cf19ab5bc98295fff3c779242f8be486ba348bd757ba920ca6579be2156",
output: "bb1650260ef2e86d96d39170f355411b6561082dcc763df0e018fdea8f10e9dc48489fb7a075f7f84260aecc10abcfadbc6e1cd26924b25dedb1cc887ada49bb4e3e02006bdd39098ef404c1c320fb3b294ded3e82b3920c8798727badfb0d63853138c29cf1ebf1759423a1457b3d2c252acf0d1cde8165f01c0b2266297e688ff03756d1b06cb79a2cc3ba649d161b8d9ef1f8fb792bd823c4eabb7fb799393f4106ab324d98",
},
{
nonce: "be0c024290af62adcd539e02",
key: "9520adab77c41e60a123c93b1adede1e5523613358485b281467fdd3c3bcf4e0",
length: 172,
nonce: [3]uint32{0x42020cbe, 0xad62af90, 0x29e53cd},
key: [8]uint32{0xabad2095, 0x601ec477, 0x3bc923a1, 0x1edede1a, 0x33612355, 0x285b4858, 0xd3fd6714, 0xe0f4bcc3},
input: "a2fc6e1b5281a4e0330eecd1ab4c41670570423173255979953142b78733b2910fa5540e8294208df6ae4f18672d5ac65acf851bcd394e1932db13c81b21e6f165e5538aff862e46126c650bbe055e54b31c78f2f0221d2631d66ef6d3f4c5ae25eada043b74d8770e2c29799c0954d8ccbd17766b79e6e94e88f478db3566a20cb890846917591a07738328d5c05f7ed4695a82607660f1239661faa9af0368aeb89726f13c2aaecf0deaf7",
output: "d8fe402a641c388522842385de98be60f87d922c318215947d4b7562d4ca1e2dbc7ee86494e65fb0bfddfdebdb2ae6469312f95b32c722b2720d64bb8d7cc3dd82f9055b1d89f05b77984f91f94ba4ac79c5129cd7c91cc751b0defc3f2799518e372d27aa683f1e7bbd4f55414c48fe8a3a37ac1f179a1a329cda775aec0d31d75a5a38addb1de67c06bddbedf4c8d87abc18c9f9dd072d457ea29ad4dfb109ce7e99a4a82fbe330b0afbb5",
},
{
nonce: "8f1c02a8c4027a6693b6687a",
key: "c801e4ec475a80faca2f576d0c781c9ce5457564114cefd7461edc914e692aba",
length: 176,
nonce: [3]uint32{0xa8021c8f, 0x667a02c4, 0x7a68b693},
key: [8]uint32{0xece401c8, 0xfa805a47, 0x6d572fca, 0x9c1c780c, 0x647545e5, 0xd7ef4c11, 0x91dc1e46, 0xba2a694e},
input: "480387bc6d2bbc9e4ced2448d9ec39a4f27abe8cfb46752d773552ad7808a794058962b49e005fef4e403e6a391d1d3f59025eeb5fb8fbbe920f5361862c205d430eac613cd66108f2f2f0bd4d95a8f6ca7bd1f917eaeb388be87d8b7084a2eb98c575034578edf1b3dafff051a59313873a7be78908599e7e1c442d883d3fd3d26787eb7467eed3a3fb2d40046a4460d5d14215565606bcf8b6270af8500e3504d6d27dacf45bace32214472d525fdc",
output: "ab81a9c28358dfe12e35a21e96f5f4190afb59214f3cf310c092ab273c63cd73a783d080c7d4db2faccd70d1180b954cd700c0a56b086691e2c2cd735c88e765e2266cd9ebe1830d63df4b34e2611a8abeeca9c8c4fac71135dafb1cb3569540ed1362ddeb744ed62f6fd21de87b836ec2980f165c02506e0c316ae3cf3d18a862954d9781f726ecc1723af4a730ccc6d6de82553450a52499acb58fb2008969401c45b2f20e12b58f308db1d199b4ff",
},
{
nonce: "7c684e41c269fcc6d312cad3",
key: "ca1cb501af5584bc4248903f52b4426064d14dcdf0f383da72b904ff0edd72f9",
length: 176,
nonce: [3]uint32{0x414e687c, 0xc6fc69c2, 0xd3ca12d3},
key: [8]uint32{0x1b51cca, 0xbc8455af, 0x3f904842, 0x6042b452, 0xcd4dd164, 0xda83f3f0, 0xff04b972, 0xf972dd0e},
input: "b274e61059f3215173ae226e30a92ee4b4f8a3da95f2e768e3fac2e54ddac92c200c525f190403a6ef9d13c0661c6a7e52ed14c73b821c9680f1f29711f28a6f3163cf762742ed9474dbea51ff94503a5a404adbbdfbf4c6041e57cb14ea90945dc6cb095a52a1c57c69c5f62ac1a91cd8784b925666335bbfee331820b5f7470bc566f8bbb303366aafe75d77c4df5de2649ed55b2e5e514c3cb9f632b567594a0cf02ec6089a950dbe00554ee4dfb9",
output: "a0969730d48ee881792a3927b2f5d279aba9f2ed01e6b31b92d0e1fb8ba7f35a236d838e0ce5f8654957167de864f324c870864b4e7450a6050cd4950aa35e5a1a34a595e88dd6f6396300aff285de369691b6e0e894106dc5b31525e4539c1e56df3ceedbbab1e85da8c0914e816270a4bae3af294b04a3ea6e9ef7e2aab4da5f5370df2706b5e3f000d88179ac756deaa652a1cc85e80ad9622f1bf91a2776262eb7289846d44f7f8192e763cb37aa",
},
{
nonce: "1d5c31dd98da35230fdaa0e0",
key: "d6c71964420f340db8f4f27a42cf3635fbc6682f5f859dac90d4c407b1b11197",
length: 183,
nonce: [3]uint32{0xdd315c1d, 0x2335da98, 0xe0a0da0f},
key: [8]uint32{0x6419c7d6, 0xd340f42, 0x7af2f4b8, 0x3536cf42, 0x2f68c6fb, 0xac9d855f, 0x7c4d490, 0x9711b1b1},
input: "ee849039c6cd972dc943d2a4468844d130c0150276f4e0889047e2300c3ecc6792c4527bfe9437dad877eb986e6b1aa9b867d1798c9d314243f0a87ec9ee5b601c2554876c87cbf50df3334a077c4152f8b8fef4a2d301ddbfa90c887ece757c3eb6c4fc1e0212d6b5a8bb038acaec28cba064c9b34f5364cb7f0fc2ac4ef2c7ddde0f5ba17014459eaa78f08a46a01882ebf7c6e409dadda250bb899dc8b3b70e160bbcb4412a9963b174d0fc6bc16383a46ffaacb6e0",
output: "3e272ded9c0a5cebe7cf17ac03f69eb20f62996e047501b6cc3c8691ddb2780ea72c21a81888bfea96e4373a412c55ca95648390de740102d661143043baec3976230e024477d134b8504a223c36a215b34164c9e9e1fa99a49fdc56f2f04ea525a6b82997d9bbc95c4b5baeab4dec50061efb7c1a757887acb8b47b142e0a2e61885a2c14c4642d83d718a0546b90699adc545a48129603862a1c89d8e665cde54b3ba487754db6d6f5acf6a4b95693cc569577a2dc48",
},
{
nonce: "7c4fb4ebddc714af7acd4345",
key: "7719e70c860e7999dcd61065e78a96379afb17295ff29e0185d082d243d02861",
length: 185,
nonce: [3]uint32{0xebb44f7c, 0xaf14c7dd, 0x4543cd7a},
key: [8]uint32{0xce71977, 0x99790e86, 0x6510d6dc, 0x37968ae7, 0x2917fb9a, 0x19ef25f, 0xd282d085, 0x6128d043},
input: "0992396a6f29b861dd0bc256e1d1b7dce88435733506a6aa20c62e43afa542d1c46e28b2e6d8e2eacb7c08db05e356fe404684b0e3a9849596db82eb788aa09258c28eb19e9838f757425b4edef12deeca56e30cf030272e325d4246d6e083219b2f965124963ca91f066d47bf5a8282a011a78b0155aa70038259a4a59135f241fd2f88c908b9f4eef7b7df0f3a1c16a52c009b522f89dabd52601bbf6e3ce68732e1a6d444469480f06da218786cf6c9666362e7a7f7be12",
output: "545c05a84b5a4fffd1dd623c8f2b11443818560bdb0c26dadd3b694d4790d294b99059f4127b7cca122c4000954d745af96094ff4623f60db33e994bb6903263d775f48d7047427b3a498c2ecde65bd37bcb8ee7e240a1e08c884c0079cab518f4e1c38ba5ea547f4da83b7c6036e4259bee91c42e8fae895df07781cc166f1d50e1550a88ee0244bb2950070714dd80a891aa8a9f0580a67a35cb44609b82a5cc7235f16deea2c4f3667f2c2b33e8eeef944e1abdc25e48fa",
},
{
nonce: "9071cb35869a2e21e43c42bc",
key: "dece19faf2e86a57ab5d05585d35b3911a50d269c223637385136c2657454f13",
length: 187,
nonce: [3]uint32{0x35cb7190, 0x212e9a86, 0xbc423ce4},
key: [8]uint32{0xfa19cede, 0x576ae8f2, 0x58055dab, 0x91b3355d, 0x69d2501a, 0x736323c2, 0x266c1385, 0x134f4557},
input: "3b9efcbbb607fad5e9f1263dad014cc5c2617d439fcd980408f4f9a93acb1a33d1c3a22f38c037e4603dfbbfb5571bc08c4a1958cbbf510e3e4dd19007fe15fad7808369149a9c4db7ca0496f7a600a6f2454ee1cffd5a68d45c270e4b53ac9b77f33a1ffbb1804244f57d2b05b8036fe2cda9efead3d4eff074ea5c07128e0b354a4a11ffa179163933bc6bd10d200804cc93b64575746e94e975f990bddcc8a4335e99e2459fbe9bc0e004ffcd6cac52f48ef55cc0637a75c1dc",
output: "631ba7301e33236da2477506ea98d3b732447389e849b68e1f09bd5fd814f40dc3247a1012fa654f08e3dda0c104ee2dff12ecf5cb018644de50d70dfb6c8cc1f5f552e5f1e50466bbb538ad6b98fd37f33fe615c326efc9cc97899b829b007f91569fa9b28ce0076c53daedf9cc0f838e22cf1125b86a6a2c2eb4a45dadea45ad00fb4f054e7d6b09c13ab1dd5328debfbf4f1b70af2b8a5b1d02df8a87d7661473e0c180ba4c815f14db87c5bdc15f11a29d8e0ce3d747d5dcd4",
},
{
nonce: "ac41c9cc025ba4dbd67a0dab",
key: "5207759b0a0927a6f0957c963f2cfff87eb9be69c1990ba383dcdd0aaf9b3f44",
length: 191,
nonce: [3]uint32{0xccc941ac, 0xdba45b02, 0xab0d7ad6},
key: [8]uint32{0x9b750752, 0xa627090a, 0x967c95f0, 0xf8ff2c3f, 0x69beb97e, 0xa30b99c1, 0xadddc83, 0x443f9baf},
input: "f28a71efd95e963e5e0bc0fcf04d8768ce93cb55dc73c32e6496022e214596314b7f843f5c7b136a371c2776a0bfbdd534dccbe7f55e9d3d3b5e938f2d7e74393e4caf6c38fa4b05c948e31dc6a9126817fa3d7892c478f75ab9f6ab85c0e12091bd06e89c7d3ca8d9dcdd4c21fead3d769a253919c2c72dd068474ea322b7e71cafa31684e05a63e179e6432fb70661792cc626a5060cec9e506b35d9286f15dc53cc220b1826314eec337dd8e7af688e5950b2316c30516620569ea65aab",
output: "1bcea54b1bf4e6e17f87e0d16388abe49b988b9c785b31f67f49f2ca4011ecd2ad5283d52ef707dd3b803e73a17663b5bfa9027710e045a0da4237f77a725cf92792b178575456de731b2971718937dd0e9ea12558c3fa06e80bbf769e9799f7470db5b91476d6175f1a6d8e974fd505854c1230b252bb892a318e6d0c24dcc9ecb4861769cd746abab58805bc41c6086a6d22b951fba57b00c5b78f6dcb2831715b9d4d788b11c06086f1d6e6279cd130bc752218d7836abc77d255a9e7a1",
},
{
nonce: "587c7e98949a83cc602e9530",
key: "6f284ae396d9dc4a12871697e8dd820ae54942010b81825ee845a4b4b0ad7995",
length: 198,
nonce: [3]uint32{0x987e7c58, 0xcc839a94, 0x30952e60},
key: [8]uint32{0xe34a286f, 0x4adcd996, 0x97168712, 0xa82dde8, 0x14249e5, 0x5e82810b, 0xb4a445e8, 0x9579adb0},
input: "c1d1ede73bd89b7c3d4ea43b7d49c065a99f789c57452670d1f92f04f2e26f4f5325c825f545016c854f2db2b3448f3dc00afe37c547d0740223515de57fd7a0861b00acfb39931dc9b1681035d69702183e4b9c6559fb8196acbf80b45e8cc5348b638c6d12cea11f6ef3cc370073c5467d0e077d2fb75e6bf89cea9e93e5cf9612862219ca743ef1696783140d833cd2147d8821a33310e3a49360cb26e393b3fee6dba08fcda38d1b7e2310ec1f715e3d8fa0c6b5e291eea07c25afd5c82759a834a89cc5",
output: "11a8493cdc495c179f0d29c2b4672997205a9080f596ee3c80d79b55162b1c875ac18eb94bf2a9e05b08024f524a1e9665912394a330c593d23260e6bdf87620c10a48f678693196fb744c49054182fba667c601e7b7ebf0f068e8d69ba004b804fda616a4a0d5350e1a3bd424b8266462be282308219c578569aefc1ccd09ecdf5da283356c9e524e14e69d25b0e19643dab26f54373a7272b43755c3f1ddaee6c5fb9e8e093110c41697e95f73a68c75454e050239197c9fbd8cec76698bd11894ebf6e2b2",
},
{
nonce: "5a021f8500c8f3e63075ae85",
key: "47be0d2d65e405dab2b3f6429ee726708066449e76f91d69a23db2f7fa2134bb",
length: 204,
nonce: [3]uint32{0x851f025a, 0xe6f3c800, 0x85ae7530},
key: [8]uint32{0x2d0dbe47, 0xda05e465, 0x42f6b3b2, 0x7026e79e, 0x9e446680, 0x691df976, 0xf7b23da2, 0xbb3421fa},
input: "37b2dc4b6a5203d3a753d2aeffcdaed5a7c1741ed04d755dd6325902128f63b6981f93c8cc540f678987f0ddb13aae6965abb975a565f0769528e2bc8c6c19d66b8934f2a39f1234f5a5e16f8f0e47789cd3042ca24d7e1d4ddb9f69d6a96e4fd648673a3a7e988a0730229512382caaded327b6bbbbd00a35df681aca21b186bc7ac3356d50889bbf891839a22bb85db4c00bfa43717b26699c485892eb5e16d1034b08d3afa61f3b5f798af502bba33d7281f2f1942b18fb733ca983244e57963615a43b64184f00a5e220",
output: "b68c7a2a1c8d8c8a03fc33495199c432726b9a1500bc5b0f8034ce32c3e3a78c42c1078e087665bd93c72a41df6bfa4e5beb63e3d3226aeeba686128229a584fab0c8c074a65cef417ad06ab1565675a41cf06bb0fb38f51204eccccb75edd724cdd16b1d65a272f939c01508f0385ca55ac68a0e145806317cc12e6848b1124943a6b2d99a8c92083fc5f31ab2e7354db3f8f2d783dbf1cfec9c54f8bfcb93d6f28ef66f18f19b0fab8836458e9b09bee742ba936cb2b747dd9dcf97ca7f6c82bf0af6f1b433592d65143fe",
},
{
nonce: "7fd9bfae2d4483f51f2fab15",
key: "9bcfd1d3e68731e457a77150b4832a416f71273f88c4fd17ed771f2756b04b6c",
length: 210,
nonce: [3]uint32{0xaebfd97f, 0xf583442d, 0x15ab2f1f},
key: [8]uint32{0xd3d1cf9b, 0xe43187e6, 0x5071a757, 0x412a83b4, 0x3f27716f, 0x17fdc488, 0x271f77ed, 0x6c4bb056},
input: "68c2c5612912b5f994172720130dff092ee85a2c1395111efa64d5a281ca864d3db9600e685854d81c6de7e8747b92fb7c4c2efa829d3d4c0c9fc9d689e2e5c84c9eae8ba4ab536fb6c7523124b9e9f2997f0b36e05fb16163d6952eee066dd22fb7585925ffded0204cc76818bcead0d1f8095ca2cf9cd1ddcd0361b9c9451940e14332dac4e870e8b2af57f8c55996447e2a8c9d548255fe3ed6c08aedaf05bb599743ecb0df8655152bbb162a52e3f21bea51cb8bf29f6df8525eb1aa9f2dd73cd3d99f4cca31f90c05316a146aab2b5b",
output: "d0ae327fa3c4d6270a2750b1125145bdeef8ab5d0a11662c25372e56f368c82c6f5fc99115a06a5968f22ffe1e4c3034c231614dd6304e6853090c5940b4d1f7905ef4588356d16d903199186167fec57e3d5ce72c900fe1330a389200ed61eec0bdc3672554f1588ec342961bf4be874139b95df66431178d1d10b178e11fcbd26963ff589d5d5faf301b7774a56bbfa836112a6ea9c3026ebdd051085f9131132c2700674bef6e6c2c5b96aace94eb2ba6c0e0aef0eefa88995e742ca51ac50af83683b801b7c2c5af4880e2b344cc5564",
},
{
nonce: "b873e9f9a7a68524e6dea72e",
key: "11efed96267ff58c3ca8e3b6c634f49e48ea07464d7ee8ac7574d8a058949c3a",
length: 216,
nonce: [3]uint32{0xf9e973b8, 0x2485a6a7, 0x2ea7dee6},
key: [8]uint32{0x96edef11, 0x8cf57f26, 0xb6e3a83c, 0x9ef434c6, 0x4607ea48, 0xace87e4d, 0xa0d87475, 0x3a9c9458},
input: "fed3d1efa309c8b50cb9da02b95167f3b77c76e0f213490a404f049270a9c105158160357b7922e6be78bc014053360534add61c2052265d9d1985022af6c2327cf2d565e9cef25a13202577948c01edc22337dc4c45defe6adbfb36385b2766e4fa7e9059b23754b1bad52e42fce76c87782918c5911f57a9394a565620d4b2d46716aa6b2ba73e9c4001298c77bfdca6e9f7df8c20807fa71278bd11d6c318ed323584978ad345c9d383b9186db3bd9cec6d128f43ff89998f315dd07fa56e2230c89d803c1c000a1b749107a3159a54398dac37487d9a",
output: "6a95fba06be8147a269599bccda0ce8f5c693398a83738512e972808ec2f25bc72402d4bcd1bc808cc7772b6e863b0e49d1d70c58fcf4fcaa442215eeb3a4648ade085177b4e7a0b0e2198f0acf5465c97bd63f93781db3f0b9a0a184c3e06a76c4793a13923f83b2242b62511c2edff00b5304584cbe317c538de23785d2504fae8faabee81c5315298186ce3dcbf63370d1ccd9efec718cbc90b3d2e0b0b6aefb3a9b31e4311f8f518be22fdc2b0f00e79a283701c53f6936dd63734ecb24480d5365d1a81392498faf9a1ddee577007acc5f8c87895be",
},
{
nonce: "444cbde3315ab7a30f0192fe",
key: "8bab05ddd17cac05203711b806475253a1ee0c8ee723eb520b73851cd51439b3",
length: 217,
nonce: [3]uint32{0xe3bd4c44, 0xa3b75a31, 0xfe92010f},
key: [8]uint32{0xdd05ab8b, 0x5ac7cd1, 0xb8113720, 0x53524706, 0x8e0ceea1, 0x52eb23e7, 0x1c85730b, 0xb33914d5},
input: "d776bee5625d29a2ebf6fec4df94d2b9ac62e8e7c56704fd38a87ee932b787cbc555621535e76ea30183cb0ee30604f485b541f45feb8c01b9750d37fded5cdffbbc34fb90fdc9c7c7ddf949a1d50b796f1ea5db437238c7fb83c4b22c9e491f75b33d84746f1cd10bfda56851b8514ff0ded0adfd5092a66a85202d06bd967485d06a2c56011110da74bf40b6e59f61b0273164744da02ce2b285d5c3f03aee79eea4d4503e517177692ed3bb035071d77fc1b95c97a4d6cc0d41462ae4a357edf478d457c4805fa586515614697e647e19271091d5734d90",
output: "60e9b2dd15da511770162345251edfb15cea929fb79285a42f6c616dfde6befc77f252e653b2d7902a403032fc4ce4934620931a2ec952a8d0f14bf1c0b65cc287b23c2300999ed993446eb416749bf0c9c7dfe60181903e5d78a92d85e7a46b5e1f824c6004d851810b0875ec7b4083e7d861aabdd251b255b3f1fd1ee64619a17d97fde45c5704ab1ef28242d607d9501709a3ac28ee7d91a3aac00cd7f27eb9e7feaf7279962b9d3468bb4367e8e725ecf168a2e1af0b0dc5ca3f5a205b8a7a2aae6534edd224efa2cf1a9cd113b372577decaaf83c1afd",
},
{
nonce: "50fdabcd995b0dd1850a169e",
key: "e9a431828b3cf3891bb1960f9dae3c85334a62f6ee2395ee5378bb28f8c68a68",
length: 218,
nonce: [3]uint32{0xcdabfd50, 0xd10d5b99, 0x9e160a85},
key: [8]uint32{0x8231a4e9, 0x89f33c8b, 0xf96b11b, 0x853cae9d, 0xf6624a33, 0xee9523ee, 0x28bb7853, 0x688ac6f8},
input: "4f57848ff5398e61bcafd4d4609bcd616ef109c0f5aa826c84f0e5055d475c6a3a90f978a38d0bd773df153179465ab6402b2c03a4bf43de1f7516eb8626d057ae1ab455316dd87f7636b15762a9e46a332645648b707b139e609b377165207bb501b8bccfa05f1bf0084631c648279afdf51c26798899777812de520f6a6f0d3c7f3ef866982f5d57f9c8d81c9a4eabb036651e8055a43c23a7f558b893dd66d8534bf8d179d8aa7d9e8987cfdaaa7b5a9381ba9c79d5c1161b1bdbd30defdd304ee07f19b7ba829a0d5b40a04b42edd6407b68399caac69069",
output: "e096cc68956ed16d2dea1154a259e01647913eeea488be0b54bd1816c781a35e161772ae1f7a26b82e864ade297a51cc9be518641b2e5f195b557ec6fc183e4e5c1fc01d84fe6ca75e5b073af8339427569b1b8ee7fcff0ffa5e7e6237987c40deec0abf091c06a3b28469c8f955fc72e4f3727557f78e8606123e0639dff782e954d55e236448f4223ff6301accda9f8fa6cd43a8d6381e5dde61851a5aec0f23aeca7262659bc793ce71fa7992f80e44611ae080b7d36066e5c75c30851306f0af514591d4d5034ecdf0d6c704bfdf85473f86141c9eb59377",
},
{
nonce: "3f32de67c92a44a0d9b1779d",
key: "d4338dcad949438381d5685e0ec3a79938607fdc638b7e69ce2e4c28fa3b3eee",
length: 219,
nonce: [3]uint32{0x67de323f, 0xa0442ac9, 0x9d77b1d9},
key: [8]uint32{0xca8d33d4, 0x834349d9, 0x5e68d581, 0x99a7c30e, 0xdc7f6038, 0x697e8b63, 0x284c2ece, 0xee3e3bfa},
input: "046a61c0f09dcbf3e3af52fab8bbcded365092fad817b66ed8ca6603b649780ed812af0150adbc8b988c43a6ada564a70df677661aff7b9f380d62977d8180d2506c63637c0585dcef6fe3f7a2cf3bbb7b3d0df7769f04bf0f2e3af9439ab7615c304b32055aea0fc060890beb34fa9f90084814b6ed7363b400dfc52ee87925c5b4a14a98e3b50c7f65adc48c89ddd6414626c5e0bdefabab85c4a0e012243e682d4931be413af62fd7123ab7e7774fcae7e423bf1d3a31d036195437e9ea8f38aa40182daa9aacf3c9f3d90cc0050977c6065c9a46bcca6ba745",
output: "cd5a6a263e3ee50dda0e34c614b94c3ec1b14b99a2f4095a6b5715fdfc3449fcdf8a09d1ae02d4c52e5e638f1ee87a4a629f99f15a23dd06718792f24285f5a415e40f698752c697ee81f2f9248da1506ce04a7f489f8e2b02e6834671a2da79acc1cdfb78ea01822d09a1c4a87ffa44e56c4f85f97507044cf946ccb6a2e06e2917bac013f608d75ee78fa422a5efc9c569226bf7068d4705fde3a9fad2030256db0acf9a1d12666e0acf9f5346ad62e5af4c01a008d67ab1224b3e98278d073116ff966cdc779fb3aff985ec9411a3eefa042d71dd4ae5b15d5e",
},
{
nonce: "5a3d6aa35fa04717b40e4405",
key: "e61e702d1a5a3d14abb967bbcc8cc8ab8fadba208be40765391b1edb801d529e",
length: 221,
nonce: [3]uint32{0xa36a3d5a, 0x1747a05f, 0x5440eb4},
key: [8]uint32{0x2d701ee6, 0x143d5a1a, 0xbb67b9ab, 0xabc88ccc, 0x20baad8f, 0x6507e48b, 0xdb1e1b39, 0x9e521d80},
input: "af516216f74a6344cbe458cbba820f7e25c0b10aa84b790da2ee6317e059171076d7246c2878be83fc00c200d546c007f849e4c163d52c7b0da31beff4abff481be3266b92e668cf4dd1c84d9d7b3e5191dcd6ddb51d17d337621046e83e9ac035fccfb239648bc3c6fd340fbb50707e5a33b3ef439d292192d0e4bc727690c61450e5a28789e5ea50e746bc66d039493e080fb70e9ae06d89004cb71de8178941c422f1e9862492fc9149a4864ff52b1277b9f5a63c2f16e9adb5263cf65a034a62ebb0f1a385d2681c87a35f1c45670b4edef1c68fe9544fcf411d95",
output: "b22ffd8f0e549bd3e0206d7f01ff222f92d39b41cf995a331d5ef0cf5c24bcc3ddb36e64d351b5755400246fe4989b5f912e18daa46cdd33e52dafbd2872f16e94220b56315d72c1dbb1525fd34831d7202970c11711ff36de3fc479407c34fef0aea86e172f9beb0f393194355b9dd59625639f4a6bf72ba571c229f2fb053c1114e82793deb2dfe8232f1a327949689d2fb2820662dcd2a39a2546c7df12b3ff7e87e58c74badf568cddebd3c558f0f7874c834c4b8aa988653f138ec79620f5e3ed737690928a30f981dca9f2920ac7307607063b40f87c204de47c",
},
{
nonce: "22e02bb9c757121e1ec0d70a",
key: "9cbb1dca0495dbaa5ca9b8775eeb0dc5b80fbc2dc24b659e5a92d89466fb9cfe",
length: 223,
nonce: [3]uint32{0xb92be022, 0x1e1257c7, 0xad7c01e},
key: [8]uint32{0xca1dbb9c, 0xaadb9504, 0x77b8a95c, 0xc50deb5e, 0x2dbc0fb8, 0x9e654bc2, 0x94d8925a, 0xfe9cfb66},
input: "a3d70bdb509f10bb28a8caab96db61652467cf4d8e608ee365699d6148d4e84d5d93bdabe29aa4f0bc8ee155f0b1fb73293c5293929eaacdd070e770c7cccfb2de120b0c3811abeeddaf77b7214a375ca67d618a5d169bb274a477421d71a651cfb9370bcf7e0d38f913754c11002089cf6cd6a8de1c8a937fb216591d57b37efdf3797f280773950f7eddeb9c3385c8315ff5ff581c64610a86ada7ff6a1657e262df94892dff9fdfb6e958d101f4c26296470c138dc4e1ca4bb565b3ff877a7f78b3d11d64b7c24e27ba6f6b06f6e368f5ac218cd5d11b815ab0987678eb",
output: "646314264896a6e25601e536f6e783d465b2ead1e0be4422bc9cc8eacabae4a749ad533eb28091be8397328dcfb34c92006bbda930ab070ed7b806095bb1c8f476350e7b08ffbd4d7d6055c8defaa8deff9d54f5215c2d7db27ce09e08f5d87a859145ea3126e2a01882921c3fddef3985bd451bca44063258390aec8ec725b07d064314fe43a9c83e9287b47616dfefbf539b82da209aa08a6d3176b7e3b4be4a17d44e581280a684e4a64414649bfcea82b541729f8178b580e8b972a89f5b8c4f9b68205e9396d8ae5e81873b61da074080fd44c52d50fb0880ee9c35da",
},
{
nonce: "27190905ba751c66ad3dc200",
key: "9d49002edb63dcaffb2ec6c3197a15b4138bce84796232859d1ee72ee4218731",
length: 224,
nonce: [3]uint32{0x5091927, 0x661c75ba, 0xc23dad},
key: [8]uint32{0x2e00499d, 0xafdc63db, 0xc3c62efb, 0xb4157a19, 0x84ce8b13, 0x85326279, 0x2ee71e9d, 0x318721e4},
input: "f48b5ae62f9968baa9ba0754276cd8e9dcfa8a88e4571856d483ee857b1e7bc98b4732e81f1b4421a3bf05ab9020d56c573474b2a2ac4a2daf0a7e0c3a692a097e746d12507ba6c47bec1d91d4c7cfc8993c6700c65a0e5f11b1ccd07a04eac41f59b15b085c1e2a38b7d3be9eb7d08984782753ae23acdafbd01ae0065ab9c6d2a2d157c1fc9c49c2444f2e5f9b0f0bbfb055cc04e29b2658b85d414b448a5b62d32af9a1e115d3d396387d4bb97ba656a9202f868b32353cc05f15ae46cbe983d47b78ba73d2578a94d149e2c64a48d0c1a04fc68baf34c24b641ea0b7a800",
output: "b9af1016275eaff9905356292944168c3fe5fdffd9e4494eb33d539b34546680936c664420769204e91ead32c2bb33a8b4868b563174d1a46108b9dfe6d9ac6cc1e975f9662c8473b14950cbc9bc2c08de19d5d0653bb460bea37b4c20a9ab118a9550bfeb1b4892a3ff774e8efe3656adcdf48239f96e844d242525ee9f9559f6a469e920dcb3eaa283a0f31f5dfac3c4fac7befa586ac31bd17f8406f5c4379ba8c3e03a6992a1915afa526d5ed8cc7d5a2605423ece9f4a44f0c41d6dc35a5d2085916ca8cabd85ac257421eb78d73451f69aaedeb4ec57840231436654ce",
},
{
nonce: "7c996d5d8739629d36de4257",
key: "eaa5b2578bd6bdc5c6b0c79960a9ae26f1755cba6bcf04a9de315068990e0f0a",
length: 227,
nonce: [3]uint32{0x5d6d997c, 0x9d623987, 0x5742de36},
key: [8]uint32{0x57b2a5ea, 0xc5bdd68b, 0x99c7b0c6, 0x26aea960, 0xba5c75f1, 0xa904cf6b, 0x685031de, 0xa0f0e99},
input: "b39101601efa2ecdf41878b0fd920a3005ce709e4ec2970abb76e32c232ea21069f81b246eda75aace7555ce8ae203455d3723e684bd671389300e353eec0d2f499d10654fafda2e7a69bfca7198eb172249167ca8864b5d5f58d28723090ec86e251a1bac0346d52fd81f06e0c05429e0b2b895588290b7d00878a4da3378eb6c7e61487de2b318fedf68fa7ad7c88ee746827c1f60d98c7716f3f9695c5ffd4670f71a0fa78a1fb554ba482c5de83feaed7c65fc71acc9f541342eb8f7622b12bb2cfa222fa2ddd8b3ed210ce442275afa3132c8a0e17dd504ecbc92525c118952be",
output: "50eb5b21c179a03b9a822f0075906a3ce4acc32486139f92635c7d834f69071d5a6dc0e15ed06a5cee37147071d59641d140a82ad5815b954e7f28e080c3dbbeaf13943d7b7c66d49d51ba1132eeadd4cb7a7e7d726d08d95f1578d55519f267f753f3e16ff39504a87b2286d8bfba0fe6bc28887b466bf276453a82cdd0abbbbf08db0e1c26c317d50ad9b8dc09cd621bc566d362024e8404739df6468869d2125c58b25d70e392f5e75924c4341be81c263915bb514ad436fb24c2c67450e84f6d1b72d1a02a3310c07a7814d930264fdbbf5ddca7067e18e8a44faa87169b7f2e35",
},
{
nonce: "07a7bc75f4d1f6897a656f2a",
key: "cc429f94483c5d2b73e40bfeaa92ac17ddd9c9bd26dff97408754826a2417b7c",
length: 233,
nonce: [3]uint32{0x75bca707, 0x89f6d1f4, 0x2a6f657a},
key: [8]uint32{0x949f42cc, 0x2b5d3c48, 0xfe0be473, 0x17ac92aa, 0xbdc9d9dd, 0x74f9df26, 0x26487508, 0x7c7b41a2},
input: "0a42f63b975ad0e12a1e32615813dfd6f79e53ce011e2a2f0534dd054689f8df73a8326fecfd517ff7fe530d78081af66c3a8c7c189eb9d9efed1e5577b5512d42ef1fe273f670ce380c64bc62e217a7e410a8ed89998344e29301e4e053a3a3cf7e71587fd056a6bd976f16e157476a06997dfaaff32172dd84190570621f2221420c0a0ea607ea756e9792c8c0e7157c95b89c9490e20b750ee85e4c27c9b8f409e848ec90afcad33342010bb9808358afbcb3d9b094127c38c243a204e76899677079758e7cbada9a5c18363449eebc07bab516a16372722403a046df85c7dd2ffc804c54d38aab",
output: "87a47bcaa1c1eb8e55151011c4f39af4b9e108a55a7124cdcf66d0dee727306e6971f783b038bd6b215f530cdbb53e17975742ec304fdb3792a88b674504396978c6a5e4a9c87a7c3ca430d61165c1a3f6162eeaf38c93e18b6ccb6a595ad428cdc98efef8f84463eed757a72ffd827b71c0579fcc1f4baa11812be2bc5a2a95df8e41d04b33343df09ce628c367d1f88488f7a2787f013c8e76f0b9257cee777ec4adc6df8c5790e41ea02da85142b777a0d4e7c7157a48118046935f8888b5352d1750bf00b92843027a349cf5685e8a2a2efde16dcf5e1c1ed8c779bb38cabfb42ec4dd87d58273",
},
{
nonce: "f7a40350de8cbd4025fb35fe",
key: "d9496e57dfe9840ea327f209e09d7c43dec86ac42b2d6a1a8476ab42b6fb5342",
length: 234,
nonce: [3]uint32{0x5003a4f7, 0x40bd8cde, 0xfe35fb25},
key: [8]uint32{0x576e49d9, 0xe84e9df, 0x9f227a3, 0x437c9de0, 0xc46ac8de, 0x1a6a2d2b, 0x42ab7684, 0x4253fbb6},
input: "abeff48fa082dfe78cac33636c421991b0d94c3bc9e5bd6d22763601a55201fa47b09ce60cb959ba107020213c28ae31d54923d1e74ab1d9ddc2762b2d23d8c6961d81068230884a39682fa4b30676ffec19319362c075df0b879a0f083a67b23597bf95c4bb997fae4736479cb8a9c00520ba2f6e5962d54c313c576180d17779ff239ad60f1f1373627770d50a1c49718b2b2e536846299e052f8c1a5d3079e91cb1b8eac4661daac32d73b3b99e2051f8f694a61d1e9d3935f802921a4d979b6ade453cf30d73a4a498a6a2c5395c60fcf271d50b4967ac12b0d7bf818c2679d552e9b3b963f9f789",
output: "a0d11e732984ad575570ed51031b8ac2d7b4c536f7e85f6fce9ef5d2b946cefe2ee009227d6747c7d133ba69609f4a1e2253d0eb59d1f930611e0c26a7c0cf2d2ce7ccea6e079eadf2eb1acf0463d90fb4b3269faae3febfc88cb9fb0873d8b74894506199394c8e44a96e6b479bd3e045749cce1c3f57243abdb37e67084eb573cd820c6cee424227019592a027e9da8f7b8997bfb292627a986f83c8fb8d156a91a12a8b52659cf9272924631745ed3a2453a4c2d87a167faa9104e799c715ed597bcb66949ab15dae29a86ba147507e8d8af66e96c09c53caa053ad3b79d9ed3c0c6c00169eaec3a3",
},
{
nonce: "ce48aec66f90f026bfb88afd",
key: "502cb8420d9e517f9850b9cb32e5756f1bf6c9e242f94a5a7b7779269c1c8e6a",
length: 237,
nonce: [3]uint32{0xc6ae48ce, 0x26f0906f, 0xfd8ab8bf},
key: [8]uint32{0x42b82c50, 0x7f519e0d, 0xcbb95098, 0x6f75e532, 0xe2c9f61b, 0x5a4af942, 0x2679777b, 0x6a8e1c9c},
input: "a77b7a5870335b9145fd2e08ec898ba2f158fda16e8a2661a7a416857b6ba6937b4843ecaa79d3635d28383af80290842de9ca0bb621ee22b7fd6bf379922741e812b1739c33dd6923d0607826fc84d46bbdbd1fe9d1255f56a167779a560a6eed1b9c9579b8f771147df467e67a070d9e9ce8ad92dc0543d1c28216c1dec82614ac5e853ed49b6abac7eb3426ef0c749febce2ca4e589d06ccfc8f9f622ede388282d69ceb2fd5122ba024b7a194da9dffc7acb481eabfcd127e9b854be1da727483452a83d1ca14238a496db89958afd7140dd057773ea9a1eee412875b552d464ba0fab31239c752d7dd3d9",
output: "b330c33a511d9809436ab0c4b84253eeda63b095d5e8dc74803de5f070444a0256d21d6c1cf82054a231b43648c3547aa37919b32cfd9893e265b55545be6d7cd11d3f238ef66c3c278fcccb7dd0dc59f57750562cb28da05d86ee30265ff6a3991a466ba7e6208c56fc8862e19ac332e5fb3cbcc84e83a6205dee61a71acd363a3c9de96d54070a69860c152d4ceb9c4b4cc3b878547b6116699885654b11f888dc3c23483a4b24fbe27c52545c06dd80ab7223d4578ab89bff5f9cbf5d55b19611a5251031df5da5060a1f198226c638ab5e8ec5db459e9cd8210f64b2521a2329d79228cc484c5065ef8a1d",
},
{
nonce: "8b6738eadaea410c7b148133",
key: "acc28f26867e2921cff89edf3452b4d4f2c4952ae36cc3cec938fad59037c47d",
length: 244,
nonce: [3]uint32{0xea38678b, 0xc41eada, 0x3381147b},
key: [8]uint32{0x268fc2ac, 0x21297e86, 0xdf9ef8cf, 0xd4b45234, 0x2a95c4f2, 0xcec36ce3, 0xd5fa38c9, 0x7dc43790},
input: "322d634bc180458123e10d0509870b54e0f0a3a72a2bd9e9cf44324c7a1ca37dd6adf9db1fcc8dadabd881f91d47d93b58382802b42ee936802fac8612ea4dd9eca5f215935ea9ba6233b9c8bddba3385861de669d95c888c8977851cb305db577a4eb2360f362fa459d61ffc8fcaa1502905b073bd8e9567ac7cff8e5fb1002c55641a3af5fc47ac0131fae372f073e19721ffcce9821e0241d7fa67bfc499c8f100e050d39bd4d7cae4557d208629603ec4a007852762ec1905d0e81b873510fd334dedcd9c288eb8415db505913af06bea94d197ab627d58f6a9944f6c56247595fc54ae3f8604aa37c3466f74561131e11dc",
output: "edbfb1090987762f75eba2439d746cdbefe8605b8ebad59e075d28b54edfe48813ccae891f6ed655c5ab5211ba896fff0c8e09bd1554aad987dc53f355d0822e9b0f524a99a79c68a9f3b4e30506cd725b07be135e4540078be88dac64fc545c433837b96a924452f6b844291c4c3fb5f8cc94f06d9f19dad7fc945f093020e82ed19f9eb3ddff68b813629991d1a460e5455e1cb41cf23bb3d96fdb6b96581c3bf9ef72814406329bbbba5b835e7724c728cebe88efcd996dea71d0fd5c53e081c21ce8b3764738d693e390fbf8e0137a716760fc9cd2014cd9bf3fd706bc3464d1f15803606976e96b1077cda0a62921ff7c32",
},
{
nonce: "84c53a88d5e7b88f66de07df",
key: "477e74c7c6883d8531a69abf8064f1788080247c3b97ff15408a5231e5869662",
length: 250,
nonce: [3]uint32{0x883ac584, 0x8fb8e7d5, 0xdf07de66},
key: [8]uint32{0xc7747e47, 0x853d88c6, 0xbf9aa631, 0x78f16480, 0x7c248080, 0x15ff973b, 0x31528a40, 0x629686e5},
input: "e6b8a9012cdfd2041ab2b65b4e4f1442794fdf1c3685e6622ce70f80b9c2252ba6d9e6384d474a7622053d35df946a3b19408b3e1712da00525070279ce381359b542a9ad7c07750e393e0834593777352c1f7dbc84cc1a2b1eba787377d2cb1d08a7d20e1393d44022107acac5d765be37f9075af02e4bbf8e60ceb262aa34e2b870cc7adcf54329a667249cb4958393bff4f4333338cae45cbca419d59e605aa0cecb1241080339198b9b283e4201afc07360b8ae2a57b0b9b97167c315f03fd7a87a00ae73f91ca560a1505f3cdf04576b9aee5ea775f719916f1e1942ad5311c7f87153f8e62855ace3f34afb08d4d7c7f4fd2bf83e42f76",
output: "fc2673c80812d101bca7a2e0e105fa449550e695a016596f5c3cde11fb7dc518b94fdb74058e634546a726c37896110e1d1f9cdeccba1c89958041061ded8e8bc2751ec6dad76a305e70c57f9c81a5a65b5116390af4f7bf7053a03ec13f5d60a58cc5ba61f8c46ef6d2d291de490082dcfdf294aeb3a9414d64e4bd6497d4625acfa591627bfd98f0aec7e7def71515c09942db6911d73b96b4bd2d6df03bb729e945d71549d40e4bc401e1f73baf263a74280537692240638619f92645a5ade1eb8151191c7ff8bd715b3c1cd667e69745b806e16d46d9aa680a7367b8fb45a1598631cf3d44c1f5cfcd95bc8dafdb65a2083905a6937fcf21",
},
{
nonce: "627acd79be19e60a36d2967d",
key: "648eec7d142bf1092adf706c0daae0ea14acb12733d8007aca0a3ce6e2389418",
length: 256,
nonce: [3]uint32{0x79cd7a62, 0xae619be, 0x7d96d236},
key: [8]uint32{0x7dec8e64, 0x9f12b14, 0x6c70df2a, 0xeae0aa0d, 0x27b1ac14, 0x7a00d833, 0xe63c0aca, 0x189438e2},
input: "0cfd93b195e37dd15dfae83132c24ed5bfce7fe6fad4064b213b2c31a39e39ddad2f977e904c9c5b055ed03db46fcdd845bbb6ff0ab5a8c92e89295b6801f36ae63eba61fba24a3858aeb36f2da226b23b24d7b2c7d2670f23a9a1b60db85c0ecee584bef1b00e42d10ca17432a74bbb220d88356d82c850da4c09dd5baf413caf8f9479e02a330065fb865489c0f59605d56146ec8434182345de2d15e2a1dceeeee2fe94871d41913f6788738947ed9849ca0ae985e3e19a97bee82b96feeddceb196c9b6012264661945981c279f43db9599a4ef01116f592478619690daa64387290484d21e8d2444751194e1f361fb37f04014a3c7e4b409e5c828d8990",
output: "0502848571d1472ff10bec06c1299fad23a2cb824d88bf91b5447c5139500bd837a2fddc629e4a964e84907c1e6740263f1fef4f5ed41062982c150d9e77a1047b7d86c0e191945e8db00ca3845a39560857fc9e0e4a394eea4ba80a689cb5714c4bab7124ffdbfa8bbb91c3eb3caa1621f49dba1eea3ebf1d547ee337f9085638a12317b86c11aa1525813445107038942fc519eebdc1b98d313ad822bf0b94a054259aa8cf1be4b3a68f974269729941747f9a23fa5d83453071b431dac62274c24f6a32248b0785ff90aad5840fadc89af0aef7553d9352cfb00d3999ffbe28cd9fde7854e95710f4532b8bf5011e518c93361e58d22a2302182e00e8bccd",
},
{
nonce: "001e58b792ba1b9a74663564",
key: "cd9f2cdc1ade505e6b464685219bb4c1cd70a63667f387280043bf2f74030af9",
length: 268,
nonce: [3]uint32{0xb7581e00, 0x9a1bba92, 0x64356674},
key: [8]uint32{0xdc2c9fcd, 0x5e50de1a, 0x8546466b, 0xc1b49b21, 0x36a670cd, 0x2887f367, 0x2fbf4300, 0xf90a0374},
input: "0d8d864010ce8df1c0179cf0236dce1c100f9c115eaa5294c24a2e1afa27f9d57ebc18f00482be0218d44262bd4db73002ff53c6388f5e333470aced2a42a73b376686c8d02e05ece27cdd8b1e3f675c715981f8b656d68d0e16227b529cf881d2433e4371fbcd933eaa72346e77e688ac80ee95324512c66a4c16338cf38c941b72c21c3d01e005a07c0eb436014fb1ee61806de7e96842ca3217ab8c7607d609dd2f637f9fda8a85cb0549f262c9e4a955c384319a6ad2b696e2593d7d174f5ddb98e2a8d5d12558c18ab67571e9a0202e91ce26d720cbe41a3a6a4f309296ca4d9d9a59a9043dd2e5a707ed7d5034023d5ea06ab14b39b7852e5c984848d5670c6f2f0b189c2a8a4a4bca",
output: "d2a5693c9d503a8821751d085a0837579233e65b691366e4a7464481d22800e786939349f721a815f28b4e47c8889f0814fb95d592d1185e45d6dbcac14ffa4f1d6c79194f2f7eb7323439d9607edf80f01e3a968b483eb93c01d9cb9d3625d21d66927e7aeedc1d9bd589560ed2b61cbed5ad0e0310c8ebe140c64c67d4909c010902d5386efa359ab60a9573493d3e5d8761cfd4023eba23de48372032d4673b5f6ad66cd0dfab02a73aa81f269ae88fcabb3ae9cb09f6bf60fd3575a3046bc6843f444e1e9fb9ff9b991620344fb99da68df09496b40f8b9dfc34e830a87f65710940603ebab554d36e8b4c9228bc9c26c07b828f34cdfdd40b161717236ba325e8c20bd018b324345e09",
},
{
nonce: "cb1f642ce2c770518836a262",
key: "1559ed5a18ccc4c57415e5f0c694d875d182701bdba12e5d24fd09079898f6f5",
length: 305,
nonce: [3]uint32{0x2c641fcb, 0x5170c7e2, 0x62a23688},
key: [8]uint32{0x5aed5915, 0xc5c4cc18, 0xf0e51574, 0x75d894c6, 0x1b7082d1, 0x5d2ea1db, 0x709fd24, 0xf5f69898},
input: "07c50a69e168e388caf6f91471cf436886a3de58ef2c44795d94fba6538add8d414d84f3ef0ac9377fd5bed6aa6805a695f3a711025550bb6f014893c664e09bd05f4d3b850771991fc02f41c7353cd062156243b67fce9c1f0c21eb73087a5de0db0578923eb49bf87a583351e8441c7b121645bcb64ef5960fdca85af863dca7ebb56662e9707d541513bc91bf9b301431423b552e2c148e66ecfd48045ecb3a940dd65694d7fc8bf511e691b9cfd7547fe7bca6465b72ff9f1748723c4eb14f8bc1efb2fbc6726115c597a3881e0d5019335daf2e5ea8796c2a8b893ca798c4ef2639465505c4bd492bf7e934bb35be9b66c9f35730736c65fa4c1a2485378b9d71912cb924634a8e0db2802b75728818dc00fc28effdf1d8a05e4de4608bb6a78bb19c377d5ec77dca1b5ad38fded7",
output: "3dff5fde2ca24bf419e13cb7d12368e70449d41f2aa22e4b567f5cbdbcf3257975e44097deb180f2621ec36acf375dad3b7a19234b9856dc6c7842a7f86be00304b41a8c1662a02e8390346cbd0ff6be7bc1ceb821dbd805ab5c93c9c6ea5093249b5dc52081cbbbe1b326e831ef3c6c42fb791790086d1586f7daf031e70a71b54e9134f942e9ce229fc77980eb80c985ee0c5965eaba375d156f9b423b0615f4ca6fd77de28e28f35aba327e4f1b75725730155b7b4d6c5c264bf3d9dc9a16e7ededcc261add8c666278bac5cf0b3275d6d6678060eae30bbf2ce5f63e6a53a450b65aa0adbd1c90cf045f5ddd9700c2a99c80586c5244cf4c08035b6ff630c82cec3a4fcc83860e987898b42fe746939f8b37c814f8dab65de276e9784fb90f0751d3ba0826889e1e7e4fdbf8a90942",
},
{
nonce: "cc72b199d056100933750548",
key: "8e39cfe66660c5c34c19ffc5c4d8d2f608891d6d6520e663cb85a4ccd63db01e",
length: 430,
nonce: [3]uint32{0x99b172cc, 0x91056d0, 0x48057533},
key: [8]uint32{0xe6cf398e, 0xc3c56066, 0xc5ff194c, 0xf6d2d8c4, 0x6d1d8908, 0x63e62065, 0xcca485cb, 0x1eb03dd6},
input: "3ddcd3c00014747903c95e49f64258615455a0b26c5070a9532382a9bbd18eeb19c9fe1a902f5c6baf544c5938fc256d310a9332223dc3c54a6eb79a4b4091c3b01c798d2800418863f2865c1cd8add760e445588576d4a6c945e1d6d50dc913674daa4737ac94d84eb0ff57cda95df915989c75adc97c4e3c1c837c798a432ba4803a246bb274b032db77e5c1bb554a5342ef2e5d3ff7f102adb5d4e282ad800ccae83f68c4bfd3b6046786a8cfaa2b63c62d64c938189b1039ae1a81ce5c91530772cca0f4a3470ba68e4e0548a221eb4addf91554e603155a4592dc5c338aa0f75a8cc2822b318fbfba4a8f73fa08512132705dae792eed6b809c251d35cca60c476406d964187b63cd59333771e37367671d0ccb393f5b8bde77bebc133485ec5c66bdd631d98cdbee78a3cf435d2f824fa2f9e91e89af28b2e155df4fb04bbe4ce0b6162dcd8e81ee8d5922ebf9c957b26c343a0396d91f6287a4af9e11b7fbb5a5a5c1fcdb186365a20617d4ff5037b0bfa97b6213a6ebcf0b78b81c65737378787b255cba03d715fed4addc2c70c1fb4d3ab16f2bff287186c26a164dae2fe9dbe3c4a2e1617f01cae79f",
output: "ecea5fc18dc4aed23359cacb8f79a457512e0a27d9816f353e315519d2b2faf74d14ae8ae5e227b203823998a47a050c363a807f45f610942fed4518b8091b88dff8b2af8fb6552eb654c85d2b6a918bcf56fb898392941d983b1afd867ef840e12313059ed3e4d217498dd511563a939c3c536fbbf8e019deed29262f0a655fc680b15939475e0cee0ce2e8bab5834f7354b93e2e0958a5bc608fab369b6aee3c9d73a6898e402484eac7300150517bbd137bf55762897696a3dc4be74b0c141755ac8f2f6e59f707b1690c451a774c46bbe195d826a6784f8d807b78f8ebc343ecacf37cb9b1b2fdbff6a1237b5098853d783e77515c419894c2628f8b5117042294ee2ed58a33746f9e79b13fdfaa25a75fc95340a89076e786e0ecad7de437a9a3fb3092146d255005b22895310b1252a3e34572cf74665b97f4adc30dd0f34e3216c7757953a4b618a775bbe68f9e0922d75afc80a1379aaf1745f2263afb6f0b37553d9c984f1ef781ea75b1980c559c77565c83f3e0bd7a3cd7cdb594658beb7e5eb940633dbc6ae2f50383beea676cb6c814b17b1d73dd133f544da88ab371415889ead21803c1ffe3f2",
},
{
nonce: "6d4adb2a1c0cd0333c19a010",
key: "df07d78b19202170815568dba3d1db9c1affb97dee19f11affc0d8b1cb224a3c",
length: 449,
nonce: [3]uint32{0x2adb4a6d, 0x33d00c1c, 0x10a0193c},
key: [8]uint32{0x8bd707df, 0x70212019, 0xdb685581, 0x9cdbd1a3, 0x7db9ff1a, 0x1af119ee, 0xb1d8c0ff, 0x3c4a22cb},
input: "93ce72a518ae892e00c271a08ead720cc4a32b676016612b5bf2b45d9ae9a27da52e664dbbdf709d9a69ba0506e2c988bb5a587400bca8ae4773bf1f315a8f383826741bfd36afeae5219796f5ce34b229cac71c066988dbcae2cbcfcdbb49efcf335380519669aaf3058e9df7f364bfd66c84703d3faaf8747442bdd35ac98acdc719011d27beba39f62eab8656060df02fab7039223f2a96caac8649bc34da45f6f224f928d69c18b281a9b3065f376858c9fd10f26658ae21f5166a50fe9a0d20739402eec84f5240ee05e61268f34408089e264e7006a59bb63eeaa629ba72603e65718d48e94e244e7b39d21d85848d5f6f417631f3876f51b76b6c264356d7d7b1b27bbac78316c5167b689eff236078cf9e2e4626a4ae8bedeecbcaf6883e2e6e9304969b4fc7a4280dcdc5196267e9bb980e225fcbf7a9b2f7098f7f5c9edd06f50c8791edaf387ff3e85ff7bee1f61e4660fddd4eaf5ab0320508e3ccaa9823ae5a71faa86bd76e16d862d83ed57bf6a13de046a3095a74a10c4da952b3c9b8fbde36048537f76eef631a83d55d3a13096e48f02b96a5a8da74c287a9164ce03ddf2f868e9ca3119ec41f0233792e64086c903eb9247dbae80e923eae",
output: "bcf49d62dcd1cff9dc37d7096df0c39031e64ccaeea3830fa485edb71b7fcf2ec709a4b327ef9c7d4ea2b35f113a8485d4c236e06b3baccee30e79c6c08739fe5fbed59db30479b56dfbe584a5d79b169b200430ed27072137e940a34170606b31f22095f2151b4d9b901f6337f991a23e4c8997a1ebf5105361fdade1c889b8dc9565e3b33e0bd608c39d725becbb60da8a797186fe0986736112da3d09906442364d6e253e5b27fd5ad72e877c120ea7a11d42b19948f0df5ddabf9cf661c5ce14b81adc2a95b6b0009ece48922b6a2b6efffdf961be8f8ec1b51ad7cfc5c1bca371f42cdac2389cbddcdc5373b6507cdf3ffc7bfb7e81487a778fcf380b934f7326b131cb568bbaa14c8f427920aa78cc0b323d6ea65260022113e2febfb93dcfce791ab6a18489e9b38de281169f1cd3b35eee0a57ed30533d7411a7e50641a78d2e80db1f872398e4ae49938b8d5aa930c0c0da2182bd176e3df56ab90af3e46cdb862cfc12070bc3bd62d6b0387e4eee66d90c50972427b34acaf2baff9d8a76002a20f43c22ac93686defc68b98b7b707d78d0e7265aabadde32507a67f425cbd16c22a426d56b9892bac3a73dd2d2c03efdb22ecc6483f8d1ca67fc7d5",
},
{
nonce: "1552f1ecdd1ae345319d4956",
key: "968498f5dfc2bc49c3a34b7bbe38515d6b46cbd6f8828ce9273f7d14f08923c8",
length: 487,
nonce: [3]uint32{0xecf15215, 0x45e31add, 0x56499d31},
key: [8]uint32{0xf5988496, 0x49bcc2df, 0x7b4ba3c3, 0x5d5138be, 0xd6cb466b, 0xe98c82f8, 0x147d3f27, 0xc82389f0},
input: "f72bec13b0f0b6f2317118f14c2a0d8e963b1bd49ae7584e710dbde75bb1e30c79281847cb822a5f3ae4fa56825e511212f17f0d293cfe80f872e6992d304e9283d08ce65ceeacb003b36a862c91282a22536e0b9c19953512a1bf9e20d3e7a8f1a2dff45dec0b9b04c592e88a7814540cf636a024d10008463d0b3aafbc4c9359889149433ef173124866aa6f53526ef3b3f2c630860ecdd08ffd9fc050e95da512cc87f812f9391085cdec5cc87258b8560806a52336d612da7ab05e0f60566b950904aa27c975a48c7d78455728c87f9b53aa4978374ab9592e12c22d9a760e26eb527133534ac5bbf969596b71cde8b4ef3587fa7ffa7116834348c275ad4dce68ab3397521ddc8e54380129cc81b981f9b32db20dddb0ecaa0f1ff7b06495a42b4a800a207b8e9ca38794e2fa9f40546e0e3aef7b5236d7fdadd72b1158714a5ad8d6264df1e75120088e449b9e911eddac59f1f19a795205ab7532783a93159876133b3fe3a518475a545fbe8dd2ac143f33c35d98e3ee13b63606b1e671917ac3ff9412773a3ac47b8c6627b8ba9dde6820f4f16c2ed9cb7d7086cfbb0cf2d7533eff253d14f634ab2aad3fb4289b9a0bb667a6fdd0acd5949185d53f1dd2b96ff060bb44f872a67259100669e6eaf1a7e2b11dd5fc35792db0c44a1127765934a068bf",
output: "bb618ae6b7739a4dedde1dbacf864b0892b93dea3007237d2f6f23be0718bdd29321e6b0fcb6a44dacf0f5c53d91e16165997e2302ae7ebc2dbd02c0fd8e8606a4ad13e409a4e807f331cf4174171c5fff23ca232192906b4eefdf2ffb4c65af78be01b0ba7d15b4341dd5a2edd49b17db2812358c8af0a4a9724e0169f50d1d331936bc2400012a60849876c3ead52cc9fe60173c9992f83f3e41ebd24fe3961835109612994c7620280539d483f91ef9a64c16032a35612a119589efe6357fa35b19531274576e304be75bc7e91d58015792095bb00ce4de251a52b946554366ea7ed9ce9317020ec155ae0071e022af36ad10eda5d671e5090c136e381cecdb8bc179474fabc7dab2d8a134772976cf0791b6cebe2333d34b4b8e2b6b2eab2b5dc7c6a08a583d091df64328cbcde36bc1b81095d82c741a1503c55d833d551a855e098166c5efffb8e4146e32e54abcaa85076ca6660abdfca9e82824217b5d3f23f7ff3455872bc76751480c1a8e3e725365c82fc135cd3713cc0f1ea733754142f8c37716a2a4fa8a6b898215c287565325774c2510df6b49e78cb986853ac5ca532c9a7e2bceb7c0157f60433f29fe29009343d6035d7b5892c77f821b644590615dc505604501dd218dcab789e6f0525387919cf25c7c6d62a8979e39d346decbed2657",
},
{
nonce: "478ca60b970002bca7147dbf",
key: "deedbe3b6c4d8f6e72cd276e60f30f14a0ef91c87f22aa4af2fe3c73f3f1512b",
length: 511,
nonce: [3]uint32{0xba68c47, 0xbc020097, 0xbf7d14a7},
key: [8]uint32{0x3bbeedde, 0x6e8f4d6c, 0x6e27cd72, 0x140ff360, 0xc891efa0, 0x4aaa227f, 0x733cfef2, 0x2b51f1f3},
input: "96eb94e1adbcc0646440c8824a2fc0f2c4b17d9cbddbb8ba8d9dbd6482fbf7201c74eb923153e0138b2f6f182f9c3d5656ee40bb7c26a01740b5c7d125261d4e4197614800aa152b402ba581bfbf4288e73c9ef7e7e37491212b921420eaaff880eeb458e3d0aa108b01b53492c97e328e9d10e3220b924351d583c00e76aee9325d6b89b1f162ffa30b386b37b5eaf4dfc25d22987dde4496158818c4d8f19ea300fe140be921d3f1abdaf9ab8946833a57cda5f41f995ff80e98b0f10f7afd736dd33438dfd395547f11563056078ff8f7c202aac262955f0ca5dae2365472de40f069028104ac552ea5a45ff2773335e5d3242f1e62e0e98003333dc51a3c8abbaf368f284536672e55d005b24b7aeba8e4cef23289adc12db2213aa037c797e7e753ae985568199cfe14cf1704fbca443e6036bdd05859e3583897cbefe7a0cf268b75d554b2da6e503ee04b126fbf74eaac0ebca37e84ab9c726973af780fe2bc9869fe67b7d9e4a04062ee535b2c1740d1347224e211b5cd37ee14c3325f40abee930eb6a1634986e756b3a1f86a3d7ee7184d95ea948506d8ab8b23f92ecf3eb0586f7a8b1bc227e08a0e32ca75ca4eeffc5c0a2a623547788bca66f3dc2c48671e462544d52a87d34307a7f111aeacb7da50262deab33d9f29dd6b47c3bb555be598d619cc66be8c4b74b01772725268a43d467f39bc565e5efcd0",
output: "590965d18ebdf1a89689662cfae1b8c8a73db8b26941313006b9b9bd6afa6a57149d09a27390b8883069e4fc2dfcf75035def1f8b865e24c21b1a1ed3e9f220d7b48046577b661bc92d9888a912984ad415ea2fc92c9e37da0bef5c7dab11495c612c27b5babe6eee28fd26482272fce69ca7f11bac95251735ad808365ac587830ec04105304f8e440a4da47d30e788718da4282941c9c76f18de4f954b8be750b54cb1145489edf273625a0df9a694a23fe7bfea12579b53c3b2a3de85705568cd7e603f3b8beba9a14cad9979ea283a8a291d3e1105b7f890e2a569804d9b7dd4c7e50bd0dcd11223fd7247af77f04212ece1b98c238d2fa0386a994bc502f83dcdd2e5a0d45b185155e1a395d91726d383c2c198fff1590e983c65ee041638510787c8c59c2e96f31678226a033e027bb40c416b73c3dbef31affc93a659c8ec7ffeca313fd5283a80533b2d63941c8f245d22b160c5fe57c5fa4b759c407b9acd6d9c4f80f244360b9acd11e2b43d4af757e16a6ef9d6756df39ca3a8a235e74351f50b2ebf54df633c8c400fd80b41b07117676d486377095660f2f20f62c034563b4560b473a8f4d6a740306d2a822fd8bd98012a840ba9b1709df9a0d61ecc305f7180fd764e334045d9a8ca23cb8036c05616a8b21fc488429ba4168c59dfa231f0ffa668a3be7b16583df1a55bb9c15d51660ddeca730d66f7a9",
},
{
nonce: "54df19942a3f5904d66dc071",
key: "4077517b5363e841089462edea2ce35fdfc56bb050b3c9ae6f2a0cc04ff4aab3",
length: 607,
nonce: [3]uint32{0x9419df54, 0x4593f2a, 0x71c06dd6},
key: [8]uint32{0x7b517740, 0x41e86353, 0xed629408, 0x5fe32cea, 0xb06bc5df, 0xaec9b350, 0xc00c2a6f, 0xb3aaf44f},
input: "be3f309c6e7b89e1ec4a855cf161156d09f8a04d5630534ee19e9e071e3f4603f23f0c59a7b7f8a32c4c203ec8c129a268faba09abde7b61135c6c37fd091e2d695f0e242488098ebed30c7d321f4dcef0bdd23fa85a53569868cf2008bf4d2ee7a12a6673298c7e797321b9f4559748223b590e6fcf17aa72251586b01181cefcd32c6a1a20a0fc27143426f6572b1aab0e7301e390cb857f912d78d5153906c698ee140b36cdc72693cc019cb7add747ca3a07b2b82a2332bfa76c962b186ad94209fcf590ed0f6a73b08a771a58eb9649f2f1da4f7c385da83d50c939231f745514d14b0920deedd9c4dc6d2e547f83643d13541870875e52c610372b14b602e7a47f0b3721cfca60ec68e2eee91f40ceba2d0fdb4ebe19cb1d1ab170726c9e600030454ef355f9a40033672be520e528937f38e7a862a5ae50cd94f667cd015a72ee3f91b1a09031bf4c207e0c516b2e7a4baedf373f1ee71843e560741ed3a3094d2b513e2248caf27ce135716f6887d9f1fe5b11e02c12c989d29054ab183a3f55d9b40d78e12ff56edf936ab966c7c3130bea472b71fd69e70165a76afbf720e2c1587a77943b35acfd81b2ab6f39476623edf3663024fb84da8057ed3a361e9533caf9fc58a5e4897e4bf84f58ed063b5c353bdca3792952eec0a1404149ebeb5b17cd6350ab3e27e44e40fbcb00780d001a48d0365d534ff830553409919608881e665f83bb5cf0736d728c41cc4e985c377f89ee1186303d0d76bc634875ab3ebd87059969f24b0464ae11967bcc47f300a34e3b917b1affceea716c5ad9abf1aa3a1106e2f4d006514dc62cfd2a52426968f2f3991c9f9d8fcd",
output: "e4032c01bcece73fde73961ed216820dcb44ce20134678c98afb674bb03afec2f4aacbade7f87a32fff57ae9213eaf0509e9d9db1313b06fd1df53561f85896ba627cccd2d0e2ae4f24f5579bf02f6599f5e63412ba084cf53a5bc9a8061b5c029b755329fcd73f629fadd3bcf6cb4c572fea86466cb5159d19eaaf0f44c3471d0323bc7206bb514ed8117a61c6d98d44faff6a83716657531d965ba3efbcf067c452e0d2807db3423958d9a4421886fe132d7c47e82086db9507616b67f0051dffc1a49ecce3ca8e4d5f5af15684cd8837a471430ddd333ea0b6ee603b7d9e702692f857fab060ccf26f2a8e61dfd3b12923acca78b83a6004e4ff09113becf6bdd0bec3a449a195559dfeafd4e2a79ead5ae3c993a15ad9b1a2ce818e18edb010b7fece9aa437d85ba9841d89026d6aac1a3a6ab6dad932a26d7db6f3664b06d51584cf4d22a75c06e2840db7292798306e4d39379af85a6bc8dcaebb5246e07fadd5e336f122de0ecb99ca24a971701a1f43bd69933beef6e52d299b132e7510caf27b99739e32bd272afc36755ea80cc7ed3957d91325584b338d15b19fe554ee70bee903babe21d0cbecd49235c70a3a4f516ce16761d1cfcd70bb4b9c7c73c359f3fdd0753d6c1ac1a1463142f18266b6a9c84675f247d56563646fb2c8c3b6b81944c2ba2b76b685ba5ea40cf539bcf3850a8af3e0a69c0b38164de520a3bea82b91f67d36bbd87877b5be7f06c2d26b2dc747a26a51f51fe293197db0e91e6ac617c71ddc6edfeb7db8f067ac2012268deb7e5f00a640c1bbec5c4c71f10f921071308cadededad5c90e72d744d0bf790b043fd35729570889ebe5",
},
{
nonce: "90bece179b25feefcad4f9bd",
key: "e8512d17c6f5805b38e4c9b9c01961a523232162896538f5a37970de43e66906",
length: 682,
nonce: [3]uint32{0x17cebe90, 0xeffe259b, 0xbdf9d4ca},
key: [8]uint32{0x172d51e8, 0x5b80f5c6, 0xb9c9e438, 0xa56119c0, 0x62212323, 0xf5386589, 0xde7079a3, 0x669e643},
input: "0aa4fbce7e1774f0607e7ea01fc0e6d210bb283964ae75e180a9f6ff3d2c4d50914bfc32bca6d243eb33551521d54d66f377fdc1d31974ece79b157905ff7e7a9b064f349727ce37c83c15ae13df635c3e6b4baf994d9aa0bb90b06c6cda51deefda72c97a2993448e654b746b216d2b949bff1af5238558205cfc3162f1d7a020a919db4d4eb44bcf7b269d4df57e24133d1e540694b9148444cee16e64035ef006a6079dff449949c1b342991f2a27f21c8bd74ccf4bc944284a46e9fd9f9bfd4b95f80c05553950fabbf5e5aed6babb8427832266aa4d175114de9127ff6ee848534d6dd5aa6d2dc361319863cdf32cfb1b074faed17d368964393352df01fe8d86af0e994bc9dac315f7d9efa7bef47a16676cdf17a535ae71d399c4c11a3a3ba0491e8d41f419685258a4ec7d1ae588b3ca341719c0827ce5f5a653959a8671844f2d0293c09bc7d35497ed18c160fc7b6d073a311b621a7a37f7ded1df3d73dcba1821278c9e17a191997fa4dab0802e1ee1b468e91e4272c4569a17dc0b2805b980bde798640aa328a3605abea1865083d7446e960c27f69d32882a2a2295efc9c440dc203872373411925f8839715e9441d31dd9cc14bab09a3e03b4a63e14db3039d58725796326ea6327f189beecd63955f1409467c81f4691ecfe9f0ac5234f23dfb84e3199e415ee7b4f67189e8857ff6cb3f64c2ac1b554bfbd679a6ea8491cfd69d96d08ee2744d9103e0b044212560ff707974b1a9043e1f2c3592828fde8ab5e993652c00e2b3fdb19082611b67866ece6c4a2635f87e04d2136d679f632416b03ece4d7e9406f3437163f4fe0c8cc7b87d487f6de3b3022665bcafa847c2b9199e1ba9af7deb0e29b66ad41688d03a8369416dfbee6d03526adb3ebc4b4f8531d73589499a3010b5309e9d9d2f5a9cf347983a92722dbf6c4f0bae8aba57b37d322",
output: "a31f9a532f35f20ba604a9ab9989260e5a4ed04e6ecfa1cb9e0e1d16943906acbbb4e761a2bebc86cad0ce8b3f26d98b455e4b0835eb8b43791cea29fe8fa6e5187b60198142059bbce98917aa2957ae2555bee70e6e9e21ff6197a51ac2ca2952c413efec4d9903a2f6883e88aebe7ca8316831f6a8f2cd0e486319b58dc8db862779adff98b7f35c33faa53d56acd7a81e0feffc286b728f3a11afab7cace4c30b1a45780276b1f0ab89242410d07cb1191c7b9da5d09db7c9a729d91ac3ed82f4350f2871a12d125ba672861d1b0af7219c360a0e023a8b7c23fb9d72631c72e032c097118d90e5db0576586d8224165a8376fe8d04de93516848e7c2653cb4f7d24a971ccf4f16c527ea5b4153fad5fd5bf473b15806671854507bf1a6d9e5fe4a6f6ec977197d21d69a041dd955e199031f895adefd850c8b0ae327ba0c18ca1783560e1ff0feb2f659137e34a91e9e9ff04fe3375b7db6e4326986e6265e5fef00297f6ae627c7563846e531762748fe8d0b6baff17acf1e6c5cfefa35a95ef634ff96f83f16342a6c62311fc653d314f8a6de109356ab7801316e69a48834cb6325816b1f66d5c67d6e9c9cbc8e1a0521fd6e4bf77a7d2609f99c9579e143f530677b99d198a97620d087f058edf35eb7271701ecebb8bfde5671641ed21aeee9e7db06b932e0def91be93cf2955159e9666c770cdffa03886eb6e98dfca8f91ff5cef1927c0f82b9226d65c68d011416cbef802c264e34244ead7a6ebbe28a510a37e1276f4f3cf27a3944a08aaa23bd321092761627dae20dc269b6150545c75e995cfee0a9bcedb1ad8b364beb8839fd5c9f7984fa0a08a1a354aebe18f62acf6d6664978fcfda2ce6fc16eaa2cda5b835339001b3b98d3a407a3e18e0ec2da6ee3d1448c1ece2ed67c3f51f01e76ed59f0e61102b103a3c65aea94275e8d1f0d331538efe",
},
{
nonce: "09bdc9b17d49e6db953bc716",
key: "e5d9f90b68e6ed2e95ca1d636de3334244e63fd8891fb199175705ef5f69e91a",
length: 768,
nonce: [3]uint32{0xb1c9bd09, 0xdbe6497d, 0x16c73b95},
key: [8]uint32{0xbf9d9e5, 0x2eede668, 0x631dca95, 0x4233e36d, 0xd83fe644, 0x99b11f89, 0xef055717, 0x1ae9695f},
input: "e097b1e8dea40f63714e63ab3ad9bdd518ac3e188926d1086a9850a5580affb592f6e421abc617c103479ba39a3924eea1c0bbbb051614c4b5003bbd5fcbb8093864fc1c130748194d6b560e203b889b98b574a98ec3e0e07cb2d9f271ba7794e5419123b4f2ebc7e0d65cd404104868905ff2c38d30c967fe9d77ebdd4b8fa836c3b0ad15e3e70e9a28236d5593e761e694b047f63bc62c7b0d493c3e2528c8af78f56725172ac9416ec2bdc54de92b92a63f9ccb61e686f9249c7cc337d99b2160400bb5535eb8f8eb1e3cafcbceaa821c1088edbacb3b01b5bed977e702de747ad00268ffe72e3d877dd75816db65b5459607cd1b963fe43bf2405ec223ddc0de514d59cde74f7522dc72285caa3eeb7eae527a7723b33d21ce91c91c8d26bf36eeb1dcdfc1e9e475c1565ed9c7e64ef601874a4f277280a5ceec26717e9385aee8b159379e3feed7952b87240c942970d63351259aa7a286ddb4a2620fa67565c92f592902e49422f1eecea2f44d1c0bbbf54a9e5612b86a9549aa3e6639a924c7bbe2d3c1b5669da73c0e2c6f6f6084f54a912ad2635d0141c2f5ac925414dce0da09ab8f86eae2a7b7e48741253189e5fd554d5c04d9807ac6ffd8a4f8229a3e8ab75ca5c778bd7ec5a5c02085faba9792cbc47f9e9311f3444e6544359769e1b3eb4d42ac8923ec94536e1a44497766b5da523f5763749dbc2738dfa8e13c191dfeac56c7614a96bd3ae23e4e6e5ac00be851ac9831108989b491eaade62113c531385ef3e964ce817c8ed0857adca946467682c2f4387fab2f31ce71b58370853171720268459588d5d216faca58d0bebbd7cd83a78445d9b49e83ec2cdb59b5d760880bf60532178d60372752b47d52562b316c7de5c74af9cd588643002d66bc6260595a540d2f82cf2c07fa64e0cdd1f79877b6a25b0608c735a7d35ca10852da441fcfb31061fd7e482a0989866f9eea8b0b39c3d519715c1c2766c3ad99f041143cdb36557ed647403458155dccbb80c3a365f0a85b1135695648ab67ac76b3d219c7b77e49d735c72ac947b1d7eeb279beb9d2602aba7b36ca",
output: "7b6e07e6415660affba56047b988f4548b308e7a642c76791f5c3742cc4cb744cde48fc30e50d458084e06c6dd29a52cb4c306a69a493a17c0838d14b107d07b81c983a2dbad09b80f087ba48465a8beaae5b16e8093e17cfb9e84ea3bdb9af00889268a5c01ddf25af434de56f65882322432aa275fac8519e317ef4d89478f29182143f97350983050f5d37c4b518611da6fa2aed7bb73e614231a194fe17c9073e377fc6ea0aa491e15ca54808e0536c8c3f1bf657283f807ebfc89b55049ac8fb86f89f17974fcf0afc1a2c690c0442842d0f4af9ee29dd960e499d1077bfdad4c0c9189a6e83799bb585acdb853c1e99da7ce9c7eeb9bf431f8d364d0ea80b0a95a7807f196c6ee69fe90e6d1f5d23e5cb256e37e65826d7a111f2272884d6319f968580b3164b2697ea6556816cea3ca316651fe2fd68dfa905d080c28622606f7d24da216289fa2c54c6f42dc244ecb047512ace62f0801f2dfad8f0218f45e2b3bbac97c2176c842398b16dfa1fdfc9a68b7b5a1e785d2a0cc592bc491f5a69c81127b758ee02c66b81674d3135c5882d1dc89dadcffa06f4b0644df5c7fd65c72611d79be7ad637edd6fc38b39946aa2a2c6d08ca9d3ff9a8ffe2e7989546489539b1a623fa937c468e59e0978602526b4367de277526895aa222fbaeae2084f418c5745d8ee844da0baa47f592970c14cf710f49539c12104a62baddb3382f5773dd18c83ecb238ae2e749a51584a38e394ebadd175bf5c3cec787907abb1d94af70ae63d3b7d8d5ff254da90b78ec8fe2ea95dfbc6e3e69ecad856c9e54906df8fe39859f2014b74dc3ca0ee2a957001939d37a6c0b489bd3f1658b835a57b24aa282c23e875c9e67e6eb8b32fe44e7d7d8e285d85da0ce1b53990f9fdb5e2e74728e433ed2c1044df9e89cb9bb316c39fc6fc8bcc74a382093926a288170e857d6b7f47858a4c2d05c74263dc9e8199332d0179687f4a4cdfc80ee6737300cefba75905b22d21e897f887b67aa3051877fff11d98bf96ca5091bb225bddd5eae697f3dfb0efcdb788ebf6694b5b39dbb0d4bf9427382a3a58f0b",
},
{
nonce: "3e507e0cdf0d11f88c6c3183",
key: "cdd1a20f05f9e74f1b4c9e2b81c85b11c5bc222925aa603f316dc21363af9620",
length: 828,
nonce: [3]uint32{0xc7e503e, 0xf8110ddf, 0x83316c8c},
key: [8]uint32{0xfa2d1cd, 0x4fe7f905, 0x2b9e4c1b, 0x115bc881, 0x2922bcc5, 0x3f60aa25, 0x13c26d31, 0x2096af63},
input: "0a1064714f20d9e47fe53250ecfec759f4137e60afaf65755f4709a483504c3855833b6dcaf7aa0180fd735fa9a73d46697f6c45004adf12452ea4c04a720fd7c20b9783b74b8b3ea0c8b1563d5a85f44af8afd7d91ca6298ca22642a684f66e365edd6f6bdb2dd32dfa13c62dc497fb341b86f65d40655931171416e23e3b2623c0b4a67d448877b6e3d4e0fe284034a10162b2b5e21639047036874f4bcde22b145b5f18aa8ff32dec81e6a5ac68b3c30c24bd8fd3b8e098a1cf202e2ab2a3bb66a9393222b9f7384653cda7707f00bc3c81e9591fd040a07d3629410c2db78781a4c9db3df5f9d648162f1b087974f56a89db07aa21ba827e3864a1618945b2fba06853a13c35da2909f5013feb313bae09870b8eab904024adab0d6ac46c1a1499791b47413139dee59db676949b9e9ab8d3d6abaa954ec2a9fc83953c91b483c3b6bd6700b96484850734e72e3710a1b379c0d0698aeaf68f13a0d317bfd689471e3299288e7a383a58522f0daaff210cc4917fa05f0b8ceefc2afc46148a05a100d30787accfb4da094e61ea6b58f132692aedcabae928e53c2594b01507b8fc2d0a85a1d111d1f4de0b95258281ae01873a72606753b6f878ecd8c4f613fb3477710d260f0bca0d4c06f675ab7113eded395f88755a98a0ad22b4a002cfe9447c4e39eda13738f4eccb9c13367ebc2878257c4647d31b67e5e32b6a77f23e9593658d19c0a40e8a7228767afba1cf23072b013b2d76ee66e42b57bec2797ce3619c695a661004c8129cb5c5d6a2836be22483f3b7e40bf8ac5535bf6cd065c4821a87829948c88163cfe3c0f60cea4e7ff59df4cdbf80064b2d664b39487413039999b5e86f1d467b12682d0cd355e9f7cd980e87d584ddbda89f68632d3b8fd6bc3b80205d7feb97a46842b093f74aa14bb21accda7474247b5e39ac76ef75e9b5b52b6a829a7e2297ab88fb0eb690d54ab1af2d7437149a6202035ce15f1e6c6267458d62677c263d83d3f8119af191b7d766582620e0f08b411c996c25ba6a32c2d73f592e789ed662e94103329bfa5e6573f1116ec04438997f3e4ad91b4123b570743455020d914bde2d8417fb24671e6db261732fb89dda1a36614b095529e4f97374c9bc0e55aa577bfffa663c816ca9fae3472e0a",
output: "b00a7caf5359c5bcebe590e6bab9aa03370050c55cbd45a257f4869937e922a15f2d38121b1493d6b5dd4a8a47d7b4e5cb049d396ad84ed421df774b0408b6939f18ebf5cf83f48c540affcc2a885967bf4bd222c42904b8a73c4185bde3f97e874fad25b46714235e60c9ff53ed2975c9c85ebad0752249e4b627ffa41555eb9074f63a5f7d61d207d2ce11b2a9fa23a13a0832eccb91efa2afd8d9acfee94ac78a733fa156bfea5006da1d0127c32aadbb75c015b68c627903e1c85bf3a1a9f99c6cfbdbb5c871f7f9661b78cf5e16d819f53e9930e201d4f58e69bcdce77ec5b9b1d2cf206a71f744342273c26b9abc71303c20df3d51f52222893d803fc8e0e0afcd99ee1c7f95b48680403566f7f9e296d7ccc0ec348b6ad515af58d11fd82c628ea29ee6a5d67aaeabd8823addc01a078b04313af73105d4ce4abef8e6ee8ce649640a19678292d4f1017d121549fd2c19ba6cdc0b613e512bc9551d759c6d38aea7e35c0847a142e273a16bb1495e652f9668b97801ba3f6d9931c0a1efaa4452e15732dca1ca9cb45ed289e0fd08d1cee1cdcc9dfba8d0b2562b0b1a180f4ee69d63573222c8d4789bf0d63d2a201a70c7b27c84e620e33e8a863cf49b784269a51ead3d4ad26f044d5859988d5485a11533ea805f5a8f6313caa6b421071a34f57170fdd8e4663e9a4cdcdcc1ddaa9f6e651fb365cf827667b018ae7d028c7f96295b2b4f9eeb4b361b48af86463a79f50b107ab0935e3cec3f4f203cea801ff95fb870d2c2f0e315dc8a6a547dd3c390a1f5403917315164bd2d40362489b389a54e8dc0ddb83e6a43a26c65923e6f76ee0ee0e3a33b0a9066620a01f0319e20b9f1beb3910ad962a3000e6aacb0ae57f3f6c5e0315be5de93edcf0e45e0e47332f9daf7f33e6e8bf1929910b78b8f88ca12bf5519a3217b7554c8c8350cc314561d580bf67a3878e3979430d070121a5e070a3458742e8549bda972f603222e2b30eb8a49a955805307e6e02f8c60a08188f69340e116422458d4a8841f46a78c833b1a822e3f6c9c97422c918f17c36175ca4b3d1c081ee4b175b4b07bf101c3836eb5b9e3cbd08a89b4a1c50edcb41ea8ea6ceb1532f5b842715d50dc21e2499e08c373d3dedb96bb477c8802ab7aa957e0b5810f38",
},
{
nonce: "c9da02eb6ca0cba74c76240c",
key: "574a41e94695e2d54c2f5e1a464c6e801f8d09481aca51437cd93e05ca95a4a6",
length: 859,
nonce: [3]uint32{0xeb02dac9, 0xa7cba06c, 0xc24764c},
key: [8]uint32{0xe9414a57, 0xd5e29546, 0x1a5e2f4c, 0x806e4c46, 0x48098d1f, 0x4351ca1a, 0x53ed97c, 0xa6a495ca},
input: "00fa3b13b5cfa9b5d65a41cc2d3c420518802c22c4582873f1ad52a22032d2cef7c975078b199787e852fb1f914529f60d1cc854e5d6d547216dce043e0fc94866bb2193343c3a07fde60e668266d1cee3067c6f2ce0f9f63456ad08094b6c7f515f7ca90caa96494e2a6835ba1f3f166012ad1ff6af6b5f8455d5c26e72402966af9066ca70ad027eed23b0eb02c751195064a62283975efeb29bc5993f83360d012a2f5275ac758a9e8fe458fc7cc0673e6b9e338678f0faff60a67fff3784c3054dcbd95d1b00ed4c6156b3831cc42a2ccdeee55541f228b88e6c318e2d797c6fc035ae12868c4a4e3843b5b25a530b1477dec3f5ac27644476b5766e0ee132d833f9a63200eb0980bf72c3666150e567e01e3e1f469cf36beea65946fce714a3f354983e54ca4315b57ea35c5f48bd5eada05f49db1004cbb39888ebab3afad62f6509abad77ca8c4ff28731c7ae545e6876c8f4a80b6cc26928ee05001a9764694b52edd605e182d5a3a5fd192bff58aba90f57e4debe612d02cf6f08af33a78ebf8823bb3eb46d4da25b7dfa15ad436c380633d3db3d0dc4dfec6c2324d105e7090e65342b554854e777b40b5dab8125a58e8b212364ff88459a8466ff5ae661034abc8286a78ad5aa582e2dabbcd7a0b0cedcb9fd5f0bb8c3bef9117f2ca6520a72b94e528c1a4a464398e654995d5f4c77cbabf2b204b96a058cf1b38284b34e41ac37b05a003ed51be9602050f21c6b9326714bc425c1e22833da95a6e77571691d4dcab4ef9056c4c7f85d5b445b902eb375b5164c6bdf629ccfd4127a6c024bb6c4da0b6b08350432e58f8229e04e2e76f704be17d36e0c04fcc7a98f721d4572aa7f66ae8e9664300a189bc3862da47b60c8b33424f6d577cc10f4755f36c2a6decc30ba81bf48f96616ccfcfb74965d6bdcab82728bb224c560d1cfd7a175413ad1c14c734746be3b062b4e7514e9075c688103515e32e3335dbd272a315024d56f4ecd354264da9bc712080657b2b51b06dc7c4c441d9858935a4c3e6b207bde38ea83bba4c6854b2bcf914d758e0a174c0528e0e385c7cff355c38db1c22440369141e91266824c59f1ed23e7d4b99d31b0baa7bed4526e24259dbef5c9ae275e97267b756645f804c274d65ac7ab0f7683435bc2e4f24075cd1b790aa2b53fbf044e8f2092bdf0dbe88a582ff8f8de291e8220",
output: "bea32587095caac661c3ac49e65654b282192b2addf5b9a403aea6c8bd0096291a0a66ca4062acf1da91fb5749952096ec63ab652ecf94c29807f0aaac939b6896edcd6f0cd8dd8d208b906ef4d7a8766831fecd6ce98f4ea0c34fa9a5114dbeb23c2cd6d3aa962e39b18cb343c24e65d49fad0a0fb50736f8d2b24b011108932484399f4c4510ac9a5e6bc78ff0b450e67f87b49f253b99d95d6294e15a9934fc8b89a5913c08f75d3516766fb0f60f82e2b2647b4619991c78adbcf548c07c0dda30c629349d84f298313c3e629e03760b1cf860264205a950d6fd86732a6513827f72c0dff5aff96f7203464f60849c1065beb70f282cca1334f6f6c767dfff94f063361f592e85597de5d313eaed17bd533db24818d9ba9aea2afa797721fbd19eea7b8d46bbc4b9dc0164636d2e754f5e9e8c04e2a381096331731c645ea1f613a37bfa9a6fb2c6307e9bacacbeab7f5672163ff9742a8115049bce0269d7d5f6f35787be031dbee1535b0516ec0b46d12f5833cde5f2cc569edcdd20993e9776aacf48ace7bfadf79065f2803fba6b2b27aa622abb7ae023ff2b27b727f509f313f92026392485a5ed4fd53b2e22b2d2dc1538ce158d34921214638be30ae054a0f5f1d4f9c590a2d215ac2a5b23ed33871ab26c8bb6db7fe9d6f51e527c9547248a4e9734c64658b22893f4f6867a35f18e2bbfd7d62142025955cb51af8e40b6fcb91c7e959cea2c92022c87c29dae107a306f41b00e73c7bceef8cb070e8f9e830caeee463170e919cba6eee63092a5a7ee33b74db09cdd022fdafbcd5d524253a29a103ba6f4d668d31d18f867557871c0e0258221c3050d57c18bdae4cc4ff8da0daddb5c08619be127ee76a317b59a9d8e67808603a1bfce6b4e0d070082b283bf9c0e6ef8256208e482f3e2d1a40d30807f60a868e2279dfbc3586d44ee25fdca3505cd39fd469c2cd03bc2f921d22a8346750f346c919e7247301c1c8a4a3ddb8eabc6e80d85cd2459afe1cbb4851ea2c86b8075e0fef3177cb074894410ecf681242fac62b5fa4ed3a10ddaa595427851d376cf69e350207b667f7aa26d003f1ec739a8792532ebd93f3cafb1fea40d227bcadda2fb6da794cea3371240f257f80b1b8a857ea453b46938397c1f4b303a46257750003a60666a11d03bf2afb5c71e059933d617288891733b63784bd9c662234f",
},
{
nonce: "a4472b3c13c814f614706fa2",
key: "183dbd3967cdaac9b58554cb226a532087ac22bb80a59d1c2e6b997d61e46f45",
length: 985,
nonce: [3]uint32{0x3c2b47a4, 0xf614c813, 0xa26f7014},
key: [8]uint32{0x39bd3d18, 0xc9aacd67, 0xcb5485b5, 0x20536a22, 0xbb22ac87, 0x1c9da580, 0x7d996b2e, 0x456fe461},
input: "01847d8a97d56e55e12f89adb13c8c0f9dea5555e8dc61171fbb8e181f6cf846a4dd68b2c75335c0896fa215bf7f9eb7e398e4520aaaf33461ecfb61051f43d43569fb75fabd79d319bf39469f951e4da7932a74624c46d8d26a9499c701c00d3dea57a6f65b4c0f33b568d13989340294d17cd005b26d89cf6fa1c88e7b6ef4d074291fa8c117ae05d7c785459ef4561c45af63a811e9aa1c31b69a5bdac2356d955a0f579791247a757a691b3de447a53619878397cd82a74053f06da3574045bc856500ec01fd2afbc64d8dd283ac876a50e9396f78c424ab157f481316fd9c90cd899f5aca46dad32c68f1d64ea7f1c4bdb994ad847072609bd89adc2fa8382a5d573b680533640b8321b6adf27926274660b2cbaf04fbc9a4fb17ce8957c38c7bab1aafd5bf7263171e47d2e1ae5cf0494815642209d303dba561754479c24ea01a573c9083b68acc49907b1748924d3c6a82feb9417ca932578c123f9db35521c0d992565f7396f0c23e436289c1720e4e7c6e285c04a8159f93e06801334e523b18fe188355cc6a155febe64ba053e6b5d1cc87787fd5ae68fa86d8c51868b9f6a9664cf0d56aa6cb8463362bb671e6b8423bcbefe2a1a0acba3f135496736b5cec5e329494af46aba322bf5d1cc108c98298459558773a316e09b0bb960a26f4b0bfbaa493b5f98a0e522b6203c471b10e662abe9b9e60de2a1517843933add02017fadd62608383ad53796159f3d21b2c8ed7295802ca79ea65d550114ca2bcc7f7c3b4c6709fffc3c2de00da06e83d8f0cf04b8c8edd21c0fc11a0b2aa7f6adad255fef25e5c0a9d59546e97446e1fbf6a51a8ea6cad54cabfdd19cd10d7d33ff0549b710557e3931821dd8809ab0a9d3aaa761a01ae0f2e378906672924d6a1b12fb1cca7bed41f31974b9917a05de60c32796f502e7035a2c01cb49bc8e1734b9fa138b81b4dfe19d37f5942dd1b42f03e1e5a6a046ecd457174150e17dd148e4bfea44b72da35ef42a7251244700e59e702033677d42611168fd246e1b18b9a464b6c20fc7fcf6360cd00466ece059a69d7d54a4f5565d08799f85dd3c849a08ba43415077c1c0e5dbdba52bb3167ee99a11db551f0260493be1dde58d2072e8c02251f4f574b6e115cbb6136dc2c3fbce75fdcefe812d9c07a91a89088985a52cb1fb9f6cef80fa30364706414175e42c75e8e37f6e7cd028c99f59caa88c49db5b46e8d6301bc39034013718a9eeef5506415016fb21d70e46a03b4c5ba72f91dd9321ff5e210e5e5f7b0723a3bc4bb02b5a74c1f4a63aa5a993a31f79a768fe8033c9abfeb4deb536af1054be02d8d1c4a6a0fa75f3eb787d57a03b7ae994fb1b54b2c43b230ce32e6245d944b3cea4fa6",
output: "785dbea5d1e50af4743ed5fd2209e441fc7c50bc7f6fd9cc7f24654c619e2606178dcbbd81a1f94c1b3176837024098bd31326145be326b32fd9277a55a6fb38780c8dc8b471a3184379d90da4aa87d80b889b1f4d8d0755c1704a526b99ac829b8ad157ca54b2b05ff8b2917e27b0c147ab54add9a89fdcad7b93ba1fe2d5be9de88b68a5324f1b42943e45ee31c4ef783ec9e2337b3f2834b10cf452b313fafdf0c03719140f64060da0a565e185cb8e544e1c185ca230ff2321739a285abe8be4be0ce76678a7b0902a77a645194de49fef8ff64cc464ea25e1f1d72c775e450f08ddd7680d27a4142879787b198583d93b84cd87fd5b4063d92d13d9c9cb580c01fac0174686a18f64e6fa0b3589624cfae04aad74950559bdf92b2b199c60cb04013aa0ef56d1f9ec5b7e968f6a83756ecc9cee7dd8b433f64649f948df5474a64549e71e46fd8bb16568d21f5fb67f5ed555f2b8aec4709383e8cbc45b9fe47c0434178ad4c6d0d42606d6eef0e21d0370898d1d5d646830a88d5f024094fe9c7a2003ca13d20ab7cd748dc11a22f578ddab416f3500eff3d89fc177b46436108e2e2c7973910cb8454a01c9e9b98f966848325444b2ac205b1ed6919fa76aaf63717574761b7f62b10649357df49f85a845a30b6acd57fa202fe58673930ec59399f537e9682b1f5f6f409988789a8e0c1f803478dded14b40d3b6eb3109758efeb6a7fe21f41c4dcc8027258da27ad74010839dbfdf8fe55050511f85c321e653f76e55f22248f46da529a380c6b1a16a19ce73af9715545c2cae098dc42dd61248dbcf7b295f4dc6b8930b41baeef677156c534869be65e723e1aa0336e8be8a3b138f840c9cd63bab6d9d61f239a47d8cf56258544e6ef65edca27069f7a57f087a7cc021fa1294b75c0c0f1093c025e426e4f041ed5187f358402676d5da5fb6ceba76a178f65c8c3046f258531c165b8808bdd221c59ff56e3e06247576e144aac01ea96a07f1be15d7a2b0b3b6c259a9133f8a50b56154ecf9f61022f470027247e6e70e6eaf7ece5e324ec8f95667ffed10337652b119e7cb8d197e306e81ea251340b9fb2c33aa230c0a16e1ca783f9344b3acbf413acd96616e6d477dba90e39326089934bc5ca6620855cdc442e25bf8b8debf335e16e7e25cceb68659cc81b13a507fbd9f30b347126beeb57016bd348fe3df592d4778011664a218227e70d7360d139480500b7f6f84153e61ca4dea105875e19ce3d11a3dfd0ad0074035ff6a9fac0ece91afd8be74c168da20c8baafcc14632eb0e774db758a3d90709cddf0266c27963788c35a842beea8ba2d916234431efde4bb32fd7e1cef51dcf580f4697206bbc3f991f4046360aea6e88ec",
},
+11 -10
View File
@@ -4,7 +4,9 @@
package chacha20
import "runtime"
import (
"runtime"
)
// Platforms that have fast unaligned 32-bit little endian accesses.
const unaligned = runtime.GOARCH == "386" ||
@@ -13,10 +15,10 @@ const unaligned = runtime.GOARCH == "386" ||
runtime.GOARCH == "ppc64le" ||
runtime.GOARCH == "s390x"
// addXor reads a little endian uint32 from src, XORs it with (a + b) and
// xor reads a little endian uint32 from src, XORs it with u and
// places the result in little endian byte order in dst.
func addXor(dst, src []byte, a, b uint32) {
_, _ = src[3], dst[3] // bounds check elimination hint
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.
@@ -27,16 +29,15 @@ func addXor(dst, src []byte, a, b uint32) {
v |= uint32(src[1]) << 8
v |= uint32(src[2]) << 16
v |= uint32(src[3]) << 24
v ^= a + b
v ^= u
dst[0] = byte(v)
dst[1] = byte(v >> 8)
dst[2] = byte(v >> 16)
dst[3] = byte(v >> 24)
} else {
a += b
dst[0] = src[0] ^ byte(a)
dst[1] = src[1] ^ byte(a>>8)
dst[2] = src[2] ^ byte(a>>16)
dst[3] = src[3] ^ byte(a>>24)
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)
}
}
-12
View File
@@ -1,12 +0,0 @@
This package runs a set of the Wycheproof tests provided by
https://github.com/google/wycheproof.
The JSON test files live in
https://github.com/google/wycheproof/tree/master/testvectors
and are being fetched and cached at a pinned version every time
these tests are run. To change the version of the wycheproof
repository that is being used for testing, update wycheproofModVer.
The structs for these tests are generated from the
schemas provided in https://github.com/google/wycheproof/tree/master/schemas
using https://github.com/a-h/generate.
-127
View File
@@ -1,127 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/aes"
"crypto/cipher"
"encoding/hex"
"fmt"
"testing"
)
func TestAesCbc(t *testing.T) {
// IndCpaTestVector
type IndCpaTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// the raw ciphertext (without IV)
Ct string `json:"ct,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the initialization vector
Iv string `json:"iv,omitempty"`
// the key
Key string `json:"key,omitempty"`
// the plaintext
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// IndCpaTestGroup
type IndCpaTestGroup struct {
// the IV size in bits
IvSize int `json:"ivSize,omitempty"`
// the keySize in bits
KeySize int `json:"keySize,omitempty"`
// the expected size of the tag in bits
TagSize int `json:"tagSize,omitempty"`
Tests []*IndCpaTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*IndCpaTestGroup `json:"testGroups,omitempty"`
}
var root Root
readTestVector(t, "aes_cbc_pkcs5_test.json", &root)
for _, tg := range root.TestGroups {
tests:
for _, tv := range tg.Tests {
block, err := aes.NewCipher(decodeHex(tv.Key))
if err != nil {
t.Fatalf("#%d: %v", tv.TcId, err)
}
mode := cipher.NewCBCDecrypter(block, decodeHex(tv.Iv))
ct := decodeHex(tv.Ct)
if len(ct)%aes.BlockSize != 0 {
panic(fmt.Sprintf("#%d: ciphertext is not a multiple of the block size", tv.TcId))
}
mode.CryptBlocks(ct, ct) // decrypt the block in place
// Skip the tests that are broken due to bad padding. Panic if there are any
// tests left that are invalid for some other reason in the future, to
// evaluate what to do with those tests.
for _, flag := range tv.Flags {
if flag == "BadPadding" {
continue tests
}
}
if !shouldPass(tv.Result, tv.Flags, nil) {
panic(fmt.Sprintf("#%d: found an invalid test that is broken for some reason other than bad padding", tv.TcId))
}
// Remove the PKCS#5 padding from the given ciphertext to validate it
padding := ct[len(ct)-1]
paddingNum := int(padding)
for i := paddingNum; i > 0; i-- {
if ct[len(ct)-i] != padding { // panic if the padding is unexpectedly bad
panic(fmt.Sprintf("#%d: bad padding at index=%d of %v", tv.TcId, i, ct))
}
}
ct = ct[:len(ct)-paddingNum]
if got, want := hex.EncodeToString(ct), tv.Msg; got != want {
t.Errorf("#%d, type: %s, comment: %q, decoded ciphertext not equal: %s, want %s", tv.TcId, tv.Result, tv.Comment, got, want)
}
}
}
}
@@ -1,148 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/cipher"
"encoding/hex"
"testing"
"golang.org/x/crypto/chacha20poly1305"
)
func TestChaCha20Poly1305(t *testing.T) {
// AeadTestVector
type AeadTestVector struct {
// additional authenticated data
Aad string `json:"aad,omitempty"`
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// the ciphertext (without iv and tag)
Ct string `json:"ct,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the nonce
Iv string `json:"iv,omitempty"`
// the key
Key string `json:"key,omitempty"`
// the plaintext
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// the authentication tag
Tag string `json:"tag,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// AeadTestGroup
type AeadTestGroup struct {
// the IV size in bits
IvSize int `json:"ivSize,omitempty"`
// the keySize in bits
KeySize int `json:"keySize,omitempty"`
// the expected size of the tag in bits
TagSize int `json:"tagSize,omitempty"`
Tests []*AeadTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*AeadTestGroup `json:"testGroups,omitempty"`
}
testAeadSealOpen := func(t *testing.T, aead cipher.AEAD, tv *AeadTestVector, recoverBadNonce func()) {
defer recoverBadNonce()
// Encrypt the message, then decrypt the new ciphertext and validate
// the decrypted message.
ciphertext := aead.Seal(nil, decodeHex(tv.Iv), decodeHex(tv.Msg), decodeHex(tv.Aad))
msg, err := aead.Open(nil, decodeHex(tv.Iv), ciphertext, decodeHex(tv.Aad))
if err != nil {
t.Fatalf("#%d: decryption failed: %v", tv.TcId, err)
}
if got, want := hex.EncodeToString(msg), tv.Msg; got != want {
t.Errorf("#%d: bad message after encrypting and decrypting: %s, want %v", tv.TcId, got, want)
}
// Decrypt the provided ciphertext and validate the decrypted message.
tv.Ct += tv.Tag // append the tag to the ciphertext
msg2, err := aead.Open(nil, decodeHex(tv.Iv), decodeHex(tv.Ct), decodeHex(tv.Aad))
wantPass := shouldPass(tv.Result, tv.Flags, nil)
if wantPass {
if err != nil {
t.Errorf("#%d, type: %s, comment: %q, decryption wanted success, got err: %v", tv.TcId, tv.Result, tv.Comment, err)
}
if got, want := hex.EncodeToString(ciphertext), tv.Ct; got != want {
t.Errorf("#%d: ciphertext doesn't match: %s, want=%s", tv.TcId, got, want)
}
if got, want := hex.EncodeToString(msg2), tv.Msg; got != want {
t.Errorf("#%d: bad message after decrypting ciphertext: %s, want %v", tv.TcId, got, want)
}
} else {
if err == nil {
t.Errorf("#%d, type: %s, comment: %q, decryption wanted error", tv.TcId, tv.Result, tv.Comment)
}
}
}
var root Root
readTestVector(t, "chacha20_poly1305_test.json", &root)
for _, tg := range root.TestGroups {
for _, tv := range tg.Tests {
aead, err := chacha20poly1305.New(decodeHex(tv.Key))
if err != nil {
t.Fatalf("#%d: %v", tv.TcId, err)
}
if tg.TagSize/8 != aead.Overhead() {
t.Fatalf("#%d: bad tag length", tv.TcId)
}
testAeadSealOpen(t, aead, tv, func() {
// A bad nonce causes a panic in AEAD.Seal and AEAD.Open,
// so should be recovered. Fail the test if it broke for
// some other reason.
if r := recover(); r != nil {
if tg.IvSize/8 == chacha20poly1305.NonceSize {
t.Errorf("#%d: unexpected panic", tv.TcId)
}
}
})
}
}
}
-123
View File
@@ -1,123 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/dsa"
"testing"
wdsa "golang.org/x/crypto/internal/wycheproof/internal/dsa"
)
func TestDsa(t *testing.T) {
// AsnSignatureTestVector
type AsnSignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// An ASN encoded signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// DsaPublicKey
type DsaPublicKey struct {
// the generator of the multiplicative subgroup
G string `json:"g,omitempty"`
// the key size in bits
KeySize int `json:"keySize,omitempty"`
// the modulus p
P string `json:"p,omitempty"`
// the order of the generator g
Q string `json:"q,omitempty"`
// the key type
Type string `json:"type,omitempty"`
// the public key value
Y string `json:"y,omitempty"`
}
// DsaTestGroup
type DsaTestGroup struct {
// unenocded DSA public key
Key *DsaPublicKey `json:"key,omitempty"`
// DER encoded public key
KeyDer string `json:"keyDer,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the hash function used for DSA
Sha string `json:"sha,omitempty"`
Tests []*AsnSignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*DsaTestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// An encoded ASN.1 integer missing a leading zero is invalid, but accepted by some implementations.
"NoLeadingZero": false,
}
var root Root
readTestVector(t, "dsa_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*dsa.PublicKey)
h := parseHash(tg.Sha).New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
hashed = hashed[:pub.Q.BitLen()/8] // Truncate to the byte-length of the subgroup (Q)
got := wdsa.VerifyASN1(pub, hashed, decodeHex(sig.Sig))
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.15
// ecdsa.VerifyASN1 was added in Go 1.15.
package wycheproof
import (
"crypto/ecdsa"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
func verifyASN1(pub *ecdsa.PublicKey, hash, sig []byte) bool {
var (
r, s = &big.Int{}, &big.Int{}
inner cryptobyte.String
)
input := cryptobyte.String(sig)
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1Integer(r) ||
!inner.ReadASN1Integer(s) ||
!inner.Empty() {
return false
}
return ecdsa.Verify(pub, hash, r, s)
}
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.15
package wycheproof
import (
"crypto/ecdsa"
)
func verifyASN1(pub *ecdsa.PublicKey, hash, sig []byte) bool {
return ecdsa.VerifyASN1(pub, hash, sig)
}
-164
View File
@@ -1,164 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/ecdsa"
"testing"
)
func TestEcdsa(t *testing.T) {
// AsnSignatureTestVector
type AsnSignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// An ASN encoded signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// EcPublicKey
type EcPublicKey struct {
// the EC group used by this public key
Curve interface{} `json:"curve,omitempty"`
// the key size in bits
KeySize int `json:"keySize,omitempty"`
// the key type
Type string `json:"type,omitempty"`
// encoded public key point
Uncompressed string `json:"uncompressed,omitempty"`
// the x-coordinate of the public key point
Wx string `json:"wx,omitempty"`
// the y-coordinate of the public key point
Wy string `json:"wy,omitempty"`
}
// EcUnnamedGroup
type EcUnnamedGroup struct {
// coefficient a of the elliptic curve equation
A string `json:"a,omitempty"`
// coefficient b of the elliptic curve equation
B string `json:"b,omitempty"`
// the x-coordinate of the generator
Gx string `json:"gx,omitempty"`
// the y-coordinate of the generator
Gy string `json:"gy,omitempty"`
// the cofactor
H int `json:"h,omitempty"`
// the order of the generator
N string `json:"n,omitempty"`
// the order of the underlying field
P string `json:"p,omitempty"`
// an unnamed EC group over a prime field in Weierstrass form
Type string `json:"type,omitempty"`
}
// EcdsaTestGroup
type EcdsaTestGroup struct {
// unenocded EC public key
Key *EcPublicKey `json:"key,omitempty"`
// DER encoded public key
KeyDer string `json:"keyDer,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the hash function used for ECDSA
Sha string `json:"sha,omitempty"`
Tests []*AsnSignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*EcdsaTestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// An encoded ASN.1 integer missing a leading zero is invalid, but accepted by some implementations.
"MissingZero": false,
// A signature using a weaker hash than the EC params is not a security risk, as long as the hash is secure.
// https://www.imperialviolet.org/2014/05/25/strengthmatching.html
"WeakHash": true,
}
// supportedCurves is a map of all elliptic curves supported
// by crypto/elliptic, which can subsequently be parsed and tested.
supportedCurves := map[string]bool{
"secp224r1": true,
"secp256r1": true,
"secp384r1": true,
"secp521r1": true,
}
var root Root
readTestVector(t, "ecdsa_test.json", &root)
for _, tg := range root.TestGroups {
curve := tg.Key.Curve.(string)
if !supportedCurves[curve] {
continue
}
pub := decodePublicKey(tg.KeyDer).(*ecdsa.PublicKey)
h := parseHash(tg.Sha).New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
got := verifyASN1(pub, hashed, decodeHex(sig.Sig))
if want := shouldPass(sig.Result, sig.Flags, flagsShouldPass); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
-100
View File
@@ -1,100 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.13
package wycheproof
import (
"testing"
"golang.org/x/crypto/ed25519"
)
func TestEddsa(t *testing.T) {
// Jwk the private key in webcrypto format
type Jwk struct {
}
// Key unencoded key pair
type Key struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// EddsaTestGroup
type EddsaTestGroup struct {
// the private key in webcrypto format
Jwk *Jwk `json:"jwk,omitempty"`
// unencoded key pair
Key *Key `json:"key,omitempty"`
// Asn encoded public key
KeyDer string `json:"keyDer,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*EddsaTestGroup `json:"testGroups,omitempty"`
}
var root Root
readTestVector(t, "eddsa_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(ed25519.PublicKey)
for _, sig := range tg.Tests {
got := ed25519.Verify(pub, decodeHex(sig.Msg), decodeHex(sig.Sig))
if want := shouldPass(sig.Result, sig.Flags, nil); got != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
-111
View File
@@ -1,111 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"bytes"
"io"
"testing"
"golang.org/x/crypto/hkdf"
)
func TestHkdf(t *testing.T) {
// HkdfTestVector
type HkdfTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the key (input key material)
Ikm string `json:"ikm,omitempty"`
// additional information used in the key derivation
Info string `json:"info,omitempty"`
// the generated bytes (output key material)
Okm string `json:"okm,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// the salt for the key derivation
Salt string `json:"salt,omitempty"`
// the size of the output in bytes
Size int `json:"size,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// HkdfTestGroup
type HkdfTestGroup struct {
// the size of the ikm in bits
KeySize int `json:"keySize,omitempty"`
Tests []*HkdfTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*HkdfTestGroup `json:"testGroups,omitempty"`
}
fileHashAlgorithms := map[string]string{
"hkdf_sha1_test.json": "SHA-1",
"hkdf_sha256_test.json": "SHA-256",
"hkdf_sha384_test.json": "SHA-384",
"hkdf_sha512_test.json": "SHA-512",
}
for f := range fileHashAlgorithms {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
for _, tv := range tg.Tests {
h := parseHash(fileHashAlgorithms[f]).New
hkdf := hkdf.New(h, decodeHex(tv.Ikm), decodeHex(tv.Salt), decodeHex(tv.Info))
key := make([]byte, tv.Size)
wantPass := shouldPass(tv.Result, tv.Flags, nil)
_, err := io.ReadFull(hkdf, key)
if (err == nil) != wantPass {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t, got: %v", tv.TcId, tv.Result, tv.Comment, wantPass, err)
}
if err != nil {
continue // don't validate output text if reading failed
}
if got, want := key, decodeHex(tv.Okm); !bytes.Equal(got, want) {
t.Errorf("tcid: %d, type: %s, comment: %q, output bytes don't match", tv.TcId, tv.Result, tv.Comment)
}
}
}
}
}
-105
View File
@@ -1,105 +0,0 @@
// Copyright 2020 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 wycheproof
import (
"crypto/hmac"
"testing"
)
func TestHMAC(t *testing.T) {
// MacTestVector
type MacTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// the key
Key string `json:"key,omitempty"`
// the plaintext
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// the authentication tag
Tag string `json:"tag,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// MacTestGroup
type MacTestGroup struct {
// the keySize in bits
KeySize int `json:"keySize,omitempty"`
// the expected size of the tag in bits
TagSize int `json:"tagSize,omitempty"`
Tests []*MacTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*MacTestGroup `json:"testGroups,omitempty"`
}
fileHashAlgs := map[string]string{
"hmac_sha1_test.json": "SHA-1",
"hmac_sha224_test.json": "SHA-224",
"hmac_sha256_test.json": "SHA-256",
"hmac_sha384_test.json": "SHA-384",
"hmac_sha512_test.json": "SHA-512",
}
for f := range fileHashAlgs {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
h := parseHash(fileHashAlgs[f])
// Skip test vectors where the tag length does not equal the
// hash length, since crypto/hmac does not support generating
// these truncated tags.
if tg.TagSize/8 != h.Size() {
continue
}
for _, tv := range tg.Tests {
hm := hmac.New(h.New, decodeHex(tv.Key))
hm.Write(decodeHex(tv.Msg))
tag := hm.Sum(nil)
got := hmac.Equal(decodeHex(tv.Tag), tag)
if want := shouldPass(tv.Result, tv.Flags, nil); want != got {
t.Errorf("%s, tcid: %d, type: %s, comment: %q, unexpected result", f, tv.TcId, tv.Result, tv.Comment)
}
}
}
}
}
-33
View File
@@ -1,33 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package dsa provides an internal version of dsa.Verify
// that is used for the Wycheproof tests.
package dsa
import (
"crypto/dsa"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
)
// VerifyASN1 verifies the ASN1 encoded signature, sig, of hash using the
// public key, pub. Its return value records whether the signature is valid.
func VerifyASN1(pub *dsa.PublicKey, hash, sig []byte) bool {
var (
r, s = &big.Int{}, &big.Int{}
inner cryptobyte.String
)
input := cryptobyte.String(sig)
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!input.Empty() ||
!inner.ReadASN1Integer(r) ||
!inner.ReadASN1Integer(s) ||
!inner.Empty() {
return false
}
return dsa.Verify(pub, hash, r, s)
}
-164
View File
@@ -1,164 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/rsa"
"testing"
)
func TestRsaPss(t *testing.T) {
// KeyJwk Public key in JWK format
type KeyJwk struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// RsassaPkcs1TestGroup
type RsassaPkcs1TestGroup struct {
// The private exponent
D string `json:"d,omitempty"`
// The public exponent
E string `json:"e,omitempty"`
// ASN encoding of the sequence [n, e]
KeyAsn string `json:"keyAsn,omitempty"`
// ASN encoding of the public key
KeyDer string `json:"keyDer,omitempty"`
// Public key in JWK format
KeyJwk *KeyJwk `json:"keyJwk,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the size of the modulus in bits
KeySize int `json:"keySize,omitempty"`
// The modulus of the key
N string `json:"n,omitempty"`
// The salt length
SLen int `json:"sLen,omitempty"`
// the hash function used for the message
Sha string `json:"sha,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*RsassaPkcs1TestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// A signature using a weaker hash than the EC params is not a security risk, as long as the hash is secure.
// https://www.imperialviolet.org/2014/05/25/strengthmatching.html
"WeakHash": true,
}
// filesOverrideToPassZeroSLen is a map of all test files
// and which TcIds that should be overriden to pass if the
// rsa.PSSOptions.SaltLength is zero.
// These tests expect a failure with a PSSOptions.SaltLength: 0
// and a signature that uses a different salt length. However,
// a salt length of 0 is defined as rsa.PSSSaltLengthAuto which
// works deterministically to auto-detect the length when
// verifying, so these tests actually pass as they should.
filesOverrideToPassZeroSLen := map[string][]int{
"rsa_pss_2048_sha1_mgf1_20_test.json": []int{46, 47},
"rsa_pss_2048_sha256_mgf1_0_test.json": []int{67, 68},
"rsa_pss_2048_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_2048_sha512_256_mgf1_28_test.json": []int{13, 14, 15},
"rsa_pss_2048_sha512_256_mgf1_32_test.json": []int{13, 14},
"rsa_pss_3072_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_4096_sha256_mgf1_32_test.json": []int{67, 68},
"rsa_pss_4096_sha512_mgf1_32_test.json": []int{136, 137},
// "rsa_pss_misc_test.json": nil, // TODO: This ones seems to be broken right now, but can enable later on.
}
for f := range filesOverrideToPassZeroSLen {
var root Root
readTestVector(t, f, &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*rsa.PublicKey)
ch := parseHash(tg.Sha)
h := ch.New()
opts := &rsa.PSSOptions{
Hash: ch,
SaltLength: rsa.PSSSaltLengthAuto,
}
// Run all the tests twice: the first time with the salt length
// as PSSSaltLengthAuto, and the second time with the salt length
// explictily set to tg.SLen.
for i := 0; i < 2; i++ {
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
err := rsa.VerifyPSS(pub, ch, hashed, decodeHex(sig.Sig), opts)
want := shouldPass(sig.Result, sig.Flags, flagsShouldPass)
if opts.SaltLength == 0 {
for _, id := range filesOverrideToPassZeroSLen[f] {
if sig.TcId == id {
want = true
break
}
}
}
if (err == nil) != want {
t.Errorf("file: %v, tcid: %d, type: %s, opts.SaltLength: %v, comment: %q, wanted success: %t", f, sig.TcId, sig.Result, opts.SaltLength, sig.Comment, want)
}
}
// Update opts.SaltLength for the second run of the tests.
opts.SaltLength = tg.SLen
}
}
}
}
-123
View File
@@ -1,123 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package wycheproof
import (
"crypto/rsa"
"testing"
)
func TestRsa(t *testing.T) {
// KeyJwk Public key in JWK format
type KeyJwk struct {
}
// Notes a description of the labels used in the test vectors
type Notes struct {
}
// SignatureTestVector
type SignatureTestVector struct {
// A brief description of the test case
Comment string `json:"comment,omitempty"`
// A list of flags
Flags []string `json:"flags,omitempty"`
// The message to sign
Msg string `json:"msg,omitempty"`
// Test result
Result string `json:"result,omitempty"`
// A signature for msg
Sig string `json:"sig,omitempty"`
// Identifier of the test case
TcId int `json:"tcId,omitempty"`
}
// RsassaPkcs1TestGroup
type RsassaPkcs1TestGroup struct {
// The private exponent
D string `json:"d,omitempty"`
// The public exponent
E string `json:"e,omitempty"`
// ASN encoding of the sequence [n, e]
KeyAsn string `json:"keyAsn,omitempty"`
// ASN encoding of the public key
KeyDer string `json:"keyDer,omitempty"`
// Public key in JWK format
KeyJwk *KeyJwk `json:"keyJwk,omitempty"`
// Pem encoded public key
KeyPem string `json:"keyPem,omitempty"`
// the size of the modulus in bits
KeySize int `json:"keySize,omitempty"`
// The modulus of the key
N string `json:"n,omitempty"`
// the hash function used for the message
Sha string `json:"sha,omitempty"`
Tests []*SignatureTestVector `json:"tests,omitempty"`
Type interface{} `json:"type,omitempty"`
}
// Root
type Root struct {
// the primitive tested in the test file
Algorithm string `json:"algorithm,omitempty"`
// the version of the test vectors.
GeneratorVersion string `json:"generatorVersion,omitempty"`
// additional documentation
Header []string `json:"header,omitempty"`
// a description of the labels used in the test vectors
Notes *Notes `json:"notes,omitempty"`
// the number of test vectors in this test
NumberOfTests int `json:"numberOfTests,omitempty"`
Schema interface{} `json:"schema,omitempty"`
TestGroups []*RsassaPkcs1TestGroup `json:"testGroups,omitempty"`
}
flagsShouldPass := map[string]bool{
// Omitting the parameter field in an ASN encoded integer is a legacy behavior.
"MissingNull": false,
// Keys with a modulus less than 2048 bits are supported by crypto/rsa.
"SmallModulus": true,
// Small public keys are supported by crypto/rsa.
"SmallPublicKey": true,
}
var root Root
readTestVector(t, "rsa_signature_test.json", &root)
for _, tg := range root.TestGroups {
pub := decodePublicKey(tg.KeyDer).(*rsa.PublicKey)
ch := parseHash(tg.Sha)
h := ch.New()
for _, sig := range tg.Tests {
h.Reset()
h.Write(decodeHex(sig.Msg))
hashed := h.Sum(nil)
err := rsa.VerifyPKCS1v15(pub, ch, hashed, decodeHex(sig.Sig))
want := shouldPass(sig.Result, sig.Flags, flagsShouldPass)
if (err == nil) != want {
t.Errorf("tcid: %d, type: %s, comment: %q, wanted success: %t", sig.TcId, sig.Result, sig.Comment, want)
}
}
}
}
-134
View File
@@ -1,134 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package wycheproof runs a set of the Wycheproof tests
// provided by https://github.com/google/wycheproof.
package wycheproof
import (
"crypto"
"crypto/x509"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"testing"
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
)
const wycheproofModVer = "v0.0.0-20191219022705-2196000605e4"
var wycheproofTestVectorsDir string
func TestMain(m *testing.M) {
if _, err := exec.LookPath("go"); err != nil {
log.Printf("skipping test because 'go' command is unavailable: %v", err)
os.Exit(0)
}
// Download the JSON test files from github.com/google/wycheproof
// using `go mod download -json` so the cached source of the testdata
// can be used in the following tests.
path := "github.com/google/wycheproof@" + wycheproofModVer
cmd := exec.Command("go", "mod", "download", "-json", path)
// TODO: enable the sumdb once the Trybots proxy supports it.
cmd.Env = append(os.Environ(), "GONOSUMDB=*")
output, err := cmd.Output()
if err != nil {
log.Fatalf("failed to run `go mod download -json %s`, output: %s", path, output)
}
var dm struct {
Dir string // absolute path to cached source root directory
}
if err := json.Unmarshal(output, &dm); err != nil {
log.Fatal(err)
}
// Now that the module has been downloaded, use the absolute path of the
// cached source as the root directory for all tests going forward.
wycheproofTestVectorsDir = filepath.Join(dm.Dir, "testvectors")
os.Exit(m.Run())
}
func readTestVector(t *testing.T, f string, dest interface{}) {
b, err := ioutil.ReadFile(filepath.Join(wycheproofTestVectorsDir, f))
if err != nil {
t.Fatalf("failed to read json file: %v", err)
}
if err := json.Unmarshal(b, &dest); err != nil {
t.Fatalf("failed to unmarshal json file: %v", err)
}
}
func decodeHex(s string) []byte {
b, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return b
}
func decodePublicKey(der string) interface{} {
d := decodeHex(der)
pub, err := x509.ParsePKIXPublicKey(d)
if err != nil {
panic(fmt.Sprintf("failed to parse DER encoded public key: %v", err))
}
return pub
}
func parseHash(h string) crypto.Hash {
switch h {
case "SHA-1":
return crypto.SHA1
case "SHA-256":
return crypto.SHA256
case "SHA-224":
return crypto.SHA224
case "SHA-384":
return crypto.SHA384
case "SHA-512":
return crypto.SHA512
case "SHA-512/224":
return crypto.SHA512_224
case "SHA-512/256":
return crypto.SHA512_256
default:
panic(fmt.Sprintf("could not identify SHA hash algorithm: %q", h))
}
}
// shouldPass returns whether or not the test should pass.
// flagsShouldPass is a map associated with whether or not
// a flag for an "acceptable" result should pass.
// Every possible flag value that's associated with an
// "acceptable" result should be explicitly specified,
// otherwise the test will panic.
func shouldPass(result string, flags []string, flagsShouldPass map[string]bool) bool {
switch result {
case "valid":
return true
case "invalid":
return false
case "acceptable":
for _, flag := range flags {
pass, ok := flagsShouldPass[flag]
if !ok {
panic(fmt.Sprintf("unspecified flag: %q", flag))
}
if !pass {
return false
}
}
return true // There are no flags, or all are meant to pass.
default:
panic(fmt.Sprintf("unexpected result: %v", result))
}
}
+2 -81
View File
@@ -31,30 +31,19 @@ Thus large amounts of data should be chunked so that each message is small.
chunk size.
This package is interoperable with NaCl: https://nacl.cr.yp.to/box.html.
Anonymous sealing/opening is an extension of NaCl defined by and interoperable
with libsodium:
https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes.
*/
package box // import "golang.org/x/crypto/nacl/box"
import (
cryptorand "crypto/rand"
"io"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/nacl/secretbox"
"golang.org/x/crypto/salsa20/salsa"
)
const (
// Overhead is the number of bytes of overhead when boxing a message.
Overhead = secretbox.Overhead
// AnonymousOverhead is the number of bytes of overhead when using anonymous
// sealed boxes.
AnonymousOverhead = Overhead + 32
)
// Overhead is the number of bytes of overhead when boxing a message.
const Overhead = secretbox.Overhead
// GenerateKey generates a new public/private key pair suitable for use with
// Seal and Open.
@@ -112,71 +101,3 @@ func Open(out, box []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte
func OpenAfterPrecomputation(out, box []byte, nonce *[24]byte, sharedKey *[32]byte) ([]byte, bool) {
return secretbox.Open(out, box, nonce, sharedKey)
}
// SealAnonymous appends an encrypted and authenticated copy of message to out,
// which will be AnonymousOverhead bytes longer than the original and must not
// overlap it. This differs from Seal in that the sender is not required to
// provide a private key.
func SealAnonymous(out, message []byte, recipient *[32]byte, rand io.Reader) ([]byte, error) {
if rand == nil {
rand = cryptorand.Reader
}
ephemeralPub, ephemeralPriv, err := GenerateKey(rand)
if err != nil {
return nil, err
}
var nonce [24]byte
if err := sealNonce(ephemeralPub, recipient, &nonce); err != nil {
return nil, err
}
if total := len(out) + AnonymousOverhead + len(message); cap(out) < total {
original := out
out = make([]byte, 0, total)
out = append(out, original...)
}
out = append(out, ephemeralPub[:]...)
return Seal(out, message, &nonce, recipient, ephemeralPriv), nil
}
// OpenAnonymous authenticates and decrypts a box produced by SealAnonymous and
// appends the message to out, which must not overlap box. The output will be
// AnonymousOverhead bytes smaller than box.
func OpenAnonymous(out, box []byte, publicKey, privateKey *[32]byte) (message []byte, ok bool) {
if len(box) < AnonymousOverhead {
return nil, false
}
var ephemeralPub [32]byte
copy(ephemeralPub[:], box[:32])
var nonce [24]byte
if err := sealNonce(&ephemeralPub, publicKey, &nonce); err != nil {
return nil, false
}
return Open(out, box[32:], &nonce, &ephemeralPub, privateKey)
}
// sealNonce generates a 24 byte nonce that is a blake2b digest of the
// ephemeral public key and the receiver's public key.
func sealNonce(ephemeralPub, peersPublicKey *[32]byte, nonce *[24]byte) error {
h, err := blake2b.New(24, nil)
if err != nil {
return err
}
if _, err = h.Write(ephemeralPub[:]); err != nil {
return err
}
if _, err = h.Write(peersPublicKey[:]); err != nil {
return err
}
h.Sum(nonce[:0])
return nil
}
-103
View File
@@ -76,106 +76,3 @@ func TestBox(t *testing.T) {
t.Fatalf("box didn't match, got\n%x\n, expected\n%x", box, expected)
}
}
func TestSealOpenAnonymous(t *testing.T) {
publicKey, privateKey, _ := GenerateKey(rand.Reader)
message := []byte("test message")
box, err := SealAnonymous(nil, message, publicKey, nil)
if err != nil {
t.Fatalf("Unexpected error sealing %v", err)
}
opened, ok := OpenAnonymous(nil, box, publicKey, privateKey)
if !ok {
t.Fatalf("failed to open box")
}
if !bytes.Equal(opened, message) {
t.Fatalf("got %x, want %x", opened, message)
}
for i := range box {
box[i] ^= 0x40
_, ok := OpenAnonymous(nil, box, publicKey, privateKey)
if ok {
t.Fatalf("opened box with byte %d corrupted", i)
}
box[i] ^= 0x40
}
// allocates new slice if out isn't long enough
out := []byte("hello")
orig := append([]byte(nil), out...)
box, err = SealAnonymous(out, message, publicKey, nil)
if err != nil {
t.Fatalf("Unexpected error sealing %v", err)
}
if !bytes.Equal(out, orig) {
t.Fatal("expected out to be unchanged")
}
if !bytes.HasPrefix(box, orig) {
t.Fatal("expected out to be coppied to returned slice")
}
_, ok = OpenAnonymous(nil, box[len(out):], publicKey, privateKey)
if !ok {
t.Fatalf("failed to open box")
}
// uses provided slice if it's long enough
out = append(make([]byte, 0, 1000), []byte("hello")...)
orig = append([]byte(nil), out...)
box, err = SealAnonymous(out, message, publicKey, nil)
if err != nil {
t.Fatalf("Unexpected error sealing %v", err)
}
if !bytes.Equal(out, orig) {
t.Fatal("expected out to be unchanged")
}
if &out[0] != &box[0] {
t.Fatal("expected box to point to out")
}
_, ok = OpenAnonymous(nil, box[len(out):], publicKey, privateKey)
if !ok {
t.Fatalf("failed to open box")
}
}
func TestSealedBox(t *testing.T) {
var privateKey [32]byte
for i := range privateKey[:] {
privateKey[i] = 1
}
var publicKey [32]byte
curve25519.ScalarBaseMult(&publicKey, &privateKey)
var message [64]byte
for i := range message[:] {
message[i] = 3
}
fakeRand := bytes.NewReader([]byte{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5})
box, err := SealAnonymous(nil, message[:], &publicKey, fakeRand)
if err != nil {
t.Fatalf("Unexpected error sealing %v", err)
}
// expected was generated using the C implementation of libsodium with a
// random implementation that always returns 5.
// https://gist.github.com/mastahyeti/942ec3f175448d68fed25018adbce5a7
expected, _ := hex.DecodeString("50a61409b1ddd0325e9b16b700e719e9772c07000b1bd7786e907c653d20495d2af1697137a53b1b1dfc9befc49b6eeb38f86be720e155eb2be61976d2efb34d67ecd44a6ad634625eb9c288bfc883431a84ab0f5557dfe673aa6f74c19f033e648a947358cfcc606397fa1747d5219a")
if !bytes.Equal(box, expected) {
t.Fatalf("box didn't match, got\n%x\n, expected\n%x", box, expected)
}
// box was generated using the C implementation of libsodium.
// https://gist.github.com/mastahyeti/942ec3f175448d68fed25018adbce5a7
box, _ = hex.DecodeString("3462e0640728247a6f581e3812850d6edc3dcad1ea5d8184c072f62fb65cb357e27ffa8b76f41656bc66a0882c4d359568410665746d27462a700f01e314f382edd7aae9064879b0f8ba7b88866f88f5e4fbd7649c850541877f9f33ebd25d46d9cbcce09b69a9ba07f0eb1d105d4264")
result, ok := OpenAnonymous(nil, box, &publicKey, &privateKey)
if !ok {
t.Fatalf("failed to open box")
}
if !bytes.Equal(result, message[:]) {
t.Fatalf("message didn't match, got\n%x\n, expected\n%x", result, message[:])
}
}
+8 -13
View File
@@ -62,11 +62,10 @@ var armorEndOfLine = []byte("-----")
// lineReader wraps a line based reader. It watches for the end of an armor
// block and records the expected CRC value.
type lineReader struct {
in *bufio.Reader
buf []byte
eof bool
crc uint32
crcSet bool
in *bufio.Reader
buf []byte
eof bool
crc uint32
}
func (l *lineReader) Read(p []byte) (n int, err error) {
@@ -88,11 +87,6 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
return 0, ArmorCorrupt
}
if bytes.HasPrefix(line, armorEnd) {
l.eof = true
return 0, io.EOF
}
if len(line) == 5 && line[0] == '=' {
// This is the checksum line
var expectedBytes [3]byte
@@ -114,7 +108,6 @@ func (l *lineReader) Read(p []byte) (n int, err error) {
}
l.eof = true
l.crcSet = true
return 0, io.EOF
}
@@ -148,8 +141,10 @@ func (r *openpgpReader) Read(p []byte) (n int, err error) {
n, err = r.b64Reader.Read(p)
r.currentCRC = crc24(r.currentCRC, p[:n])
if err == io.EOF && r.lReader.crcSet && r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
return 0, ArmorCorrupt
if err == io.EOF {
if r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
return 0, ArmorCorrupt
}
}
return
-76
View File
@@ -7,7 +7,6 @@ package clearsign
import (
"bytes"
"fmt"
"io"
"testing"
"golang.org/x/crypto/openpgp"
@@ -192,22 +191,6 @@ func TestMultiSign(t *testing.T) {
}
}
func TestDecodeMissingCRC(t *testing.T) {
block, rest := Decode(clearsignInput3)
if block == nil {
t.Fatal("failed to decode PGP signature missing a CRC")
}
if len(rest) > 0 {
t.Fatalf("Decode should not have any remaining data left: %s", rest)
}
if _, err := packet.Read(block.ArmoredSignature.Body); err != nil {
t.Error(err)
}
if _, err := packet.Read(block.ArmoredSignature.Body); err != io.EOF {
t.Error(err)
}
}
const signatureBlock = `
-----BEGIN PGP SIGNATURE-----
Version: OpenPrivacy 0.99
@@ -303,65 +286,6 @@ qZg6BaTvOxepqOxnhVU=
trailing`)
var clearsignInput3 = []byte(`-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
Origin: vscode stable
Label: vscode stable
Suite: stable
Codename: stable
Date: Mon, 13 Jan 2020 08:41:45 UTC
Architectures: amd64
Components: main
Description: Generated by aptly
MD5Sum:
66437152b3082616d8053e52c4bafafb 5821166 Contents-amd64
8024662ed51109946a517754bbafdd33 286298 Contents-amd64.gz
66437152b3082616d8053e52c4bafafb 5821166 main/Contents-amd64
8024662ed51109946a517754bbafdd33 286298 main/Contents-amd64.gz
3062a08b3eca94a65d6d17ba1dafcf3e 1088265 main/binary-amd64/Packages
b8ee22200fba8fa3be56c1ff946cdd24 159344 main/binary-amd64/Packages.bz2
f89c47c81ebd25caf287c8e6dda16c1a 169456 main/binary-amd64/Packages.gz
4c9ca25b556f111a5536c78df885ad82 95 main/binary-amd64/Release
SHA1:
2b62d0e322746b7d094878278f49993ca4314bf7 5821166 Contents-amd64
aafe35cce12e03d8b1939e403ddf5c0958c6e9bd 286298 Contents-amd64.gz
2b62d0e322746b7d094878278f49993ca4314bf7 5821166 main/Contents-amd64
aafe35cce12e03d8b1939e403ddf5c0958c6e9bd 286298 main/Contents-amd64.gz
30316ac5d4ce3b472a96a797eeb0a2a82d43ed3e 1088265 main/binary-amd64/Packages
6507e0b4da8194fd1048fcbb74c6e7433edaf3d6 159344 main/binary-amd64/Packages.bz2
ec9d39c39567c74001221e4900fb5d11ec11b833 169456 main/binary-amd64/Packages.gz
58bf20987a91d35936f18efce75ea233d43dbf8b 95 main/binary-amd64/Release
SHA256:
deff9ebfc44bf482e10a6ea10f608c6bb0fdc8373bf86b88cad9d99879ae3c39 5821166 Contents-amd64
f163bc65c7666ef58e0be3336e8c846ae2b7b388fbb2d7db0bcdc3fd1abae462 286298 Contents-amd64.gz
deff9ebfc44bf482e10a6ea10f608c6bb0fdc8373bf86b88cad9d99879ae3c39 5821166 main/Contents-amd64
f163bc65c7666ef58e0be3336e8c846ae2b7b388fbb2d7db0bcdc3fd1abae462 286298 main/Contents-amd64.gz
0fba50799ef72d0c2b354d0bcbbc8c623f6dae5a7fd7c218a54ea44dd8a49d5e 1088265 main/binary-amd64/Packages
69382470a88b67acde80fe45ab223016adebc445713ff0aa3272902581d21f13 159344 main/binary-amd64/Packages.bz2
1724b8ace5bd8882943e9463d8525006f33ca704480da0186fd47937451dc216 169456 main/binary-amd64/Packages.gz
0f509a0cb07e0ab433176fa47a21dccccc6b519f25f640cc58561104c11de6c2 95 main/binary-amd64/Release
SHA512:
f69f09c6180ceb6625a84b5f7123ad27972983146979dcfd9c38b2990459b52b4975716f85374511486bb5ad5852ebb1ef8265176df7134fc15b17ada3ba596c 5821166 Contents-amd64
46031bf89166188989368957d20cdcaac6eec72bab3f9839c9704bb08cbee3174ca6da11e290b0eab0e6b5754c1e7feb06d18ec9c5a0c955029cef53235e0a3a 286298 Contents-amd64.gz
f69f09c6180ceb6625a84b5f7123ad27972983146979dcfd9c38b2990459b52b4975716f85374511486bb5ad5852ebb1ef8265176df7134fc15b17ada3ba596c 5821166 main/Contents-amd64
46031bf89166188989368957d20cdcaac6eec72bab3f9839c9704bb08cbee3174ca6da11e290b0eab0e6b5754c1e7feb06d18ec9c5a0c955029cef53235e0a3a 286298 main/Contents-amd64.gz
3f78baf5adbaf0100996555b154807c794622fd0b5879b568ae0b6560e988fbfabed8d97db5a703d1a58514b9690fc6b60f9ad2eeece473d86ab257becd0ae41 1088265 main/binary-amd64/Packages
18f26df90beff29192662ca40525367c3c04f4581d59d2e9ab1cd0700a145b6a292a1609ca33ebe1c211f13718a8eee751f41fd8189cf93d52aa3e0851542dfc 159344 main/binary-amd64/Packages.bz2
6a6d917229e0cf06c493e174a87d76e815717676f2c70bcbd3bc689a80bd3c5489ea97db83b8f74cba8e70f374f9d9974f22b1ed2687a4ba1dacd22fdef7e14d 169456 main/binary-amd64/Packages.gz
e1a4378ad266c13c2edf8a0e590fa4d11973ab99ce79f15af005cb838f1600f66f3dc6da8976fa8b474da9073c118039c27623ab3360c6df115071497fe4f50c 95 main/binary-amd64/Release
-----BEGIN PGP SIGNATURE-----
Version: BSN Pgp v1.0.0.0
iQEcBAEBCAAGBQJeHC1bAAoJEOs+lK2+EinPAg8H/1rrhcgfm1HYL+Vmr9Ns6ton
LWQ8r13ADN66UTRa3XsO9V+q1fYowTqpXq6EZt2Gmlby/cpDf7mFPM5IteOXWLl7
QcWxPKHcdPIUi+h5F7BkFW65imP9GyX+V5Pxx5X544op7hYKaI0gAQ1oYtWDb3HE
4D27fju6icbj8w6E8TePcrDn82UvWAcaI5WSLboyhXCt2DxS3PNGFlyaP58zKJ8F
9cbBzksuMgMaTPAAMrU0zrFGfGeQz0Yo6nV/gRGiQaL9pSeIJWSKLNCMG/nIGmv2
xHVNFqTEetREY6UcQmuhwOn4HezyigH6XCBVp/Uez1izXiNdwBOet34SSvnkuJ4=
-----END PGP SIGNATURE-----`)
var signingKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
Version: GnuPG v1.4.10 (GNU/Linux)
+1 -3
View File
@@ -76,9 +76,7 @@ func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err
// Bleichenbacher, Advances in Cryptology (Crypto '98),
func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
s := new(big.Int).Exp(c1, priv.X, priv.P)
if s.ModInverse(s, priv.P) == nil {
return nil, errors.New("elgamal: invalid private key")
}
s.ModInverse(s, priv.P)
s.Mul(s, c2)
s.Mod(s, priv.P)
em := s.Bytes()
-15
View File
@@ -47,18 +47,3 @@ func TestEncryptDecrypt(t *testing.T) {
t.Errorf("decryption failed, got: %x, want: %x", message2, message)
}
}
func TestDecryptBadKey(t *testing.T) {
priv := &PrivateKey{
PublicKey: PublicKey{
G: fromHex(generatorHex),
P: fromHex("2"),
},
X: fromHex("42"),
}
priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
c1, c2 := fromHex("8"), fromHex("8")
if _, err := Decrypt(priv, c1, c2); err == nil {
t.Errorf("unexpected success decrypting")
}
}
+2 -4
View File
@@ -5,7 +5,6 @@
package packet
import (
"crypto"
"crypto/rsa"
"encoding/binary"
"io"
@@ -79,9 +78,8 @@ func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
// padding oracle attacks.
switch priv.PubKeyAlgo {
case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
// Supports both *rsa.PrivateKey and crypto.Decrypter
k := priv.PrivateKey.(crypto.Decrypter)
b, err = k.Decrypt(config.Random(), padToKeySize(k.Public().(*rsa.PublicKey), e.encryptedMPI1.bytes), nil)
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)
-69
View File
@@ -6,11 +6,9 @@ package packet
import (
"bytes"
"crypto"
"crypto/rsa"
"encoding/hex"
"fmt"
"io"
"math/big"
"testing"
)
@@ -82,73 +80,6 @@ func TestDecryptingEncryptedKey(t *testing.T) {
}
}
type rsaDecrypter struct {
rsaPrivateKey *rsa.PrivateKey
decryptCount int
}
func (r *rsaDecrypter) Public() crypto.PublicKey {
return &r.rsaPrivateKey.PublicKey
}
func (r *rsaDecrypter) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
r.decryptCount++
return r.rsaPrivateKey.Decrypt(rand, msg, opts)
}
func TestRSADecrypter(t *testing.T) {
const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
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
}
if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
customDecrypter := &rsaDecrypter{
rsaPrivateKey: encryptedKeyRSAPriv,
}
customKeyPriv := &PrivateKey{
PublicKey: PublicKey{
PubKeyAlgo: PubKeyAlgoRSA,
},
PrivateKey: customDecrypter,
}
err = ek.Decrypt(customKeyPriv, nil)
if err != nil {
t.Errorf("error from Decrypt: %s", err)
return
}
if ek.CipherFunc != CipherAES256 {
t.Errorf("unexpected EncryptedKey contents: %#v", ek)
return
}
keyHex := fmt.Sprintf("%x", ek.Key)
if keyHex != expectedKeyHex {
t.Errorf("bad key, got %s want %s", keyHex, expectedKeyHex)
}
if customDecrypter.decryptCount != 1 {
t.Errorf("Expected customDecrypter.Decrypt() to be called 1 time, but was called %d times", customDecrypter.decryptCount)
}
}
func TestEncryptingEncryptedKey(t *testing.T) {
key := []byte{1, 2, 3, 4}
const expectedKeyHex = "01020304"
+17 -50
View File
@@ -14,7 +14,6 @@ import (
"crypto/rsa"
"io"
"math/big"
"math/bits"
"golang.org/x/crypto/cast5"
"golang.org/x/crypto/openpgp/errors"
@@ -101,65 +100,33 @@ func (r *partialLengthReader) Read(p []byte) (n int, err error) {
type partialLengthWriter struct {
w io.WriteCloser
lengthByte [1]byte
sentFirst bool
buf []byte
}
// RFC 4880 4.2.2.4: the first partial length MUST be at least 512 octets long.
const minFirstPartialWrite = 512
func (w *partialLengthWriter) Write(p []byte) (n int, err error) {
off := 0
if !w.sentFirst {
if len(w.buf) > 0 || len(p) < minFirstPartialWrite {
off = len(w.buf)
w.buf = append(w.buf, p...)
if len(w.buf) < minFirstPartialWrite {
return len(p), nil
}
p = w.buf
w.buf = nil
}
w.sentFirst = true
}
power := uint8(30)
for len(p) > 0 {
l := 1 << power
if len(p) < l {
power = uint8(bits.Len32(uint32(len(p)))) - 1
l = 1 << power
}
w.lengthByte[0] = 224 + power
_, err = w.w.Write(w.lengthByte[:])
if err == nil {
var m int
m, err = w.w.Write(p[:l])
n += m
}
if err != nil {
if n < off {
return 0, err
for power := uint(14); power < 32; power-- {
l := 1 << power
if len(p) >= l {
w.lengthByte[0] = 224 + uint8(power)
_, err = w.w.Write(w.lengthByte[:])
if err != nil {
return
}
var m int
m, err = w.w.Write(p[:l])
n += m
if err != nil {
return
}
p = p[l:]
break
}
return n - off, err
}
p = p[l:]
}
return n - off, nil
return
}
func (w *partialLengthWriter) Close() error {
if len(w.buf) > 0 {
// In this case we can't send a 512 byte packet.
// Just send what we have.
p := w.buf
w.sentFirst = true
w.buf = nil
if _, err := w.Write(p); err != nil {
return err
}
}
w.lengthByte[0] = 0
_, err := w.w.Write(w.lengthByte[:])
if err != nil {
+1 -37
View File
@@ -232,21 +232,7 @@ func TestPartialLengths(t *testing.T) {
t.Errorf("error from write: %s", err)
}
}
if err := w.Close(); err != nil {
t.Fatal(err)
}
// The first packet should be at least 512 bytes.
first, err := buf.ReadByte()
if err != nil {
t.Fatal(err)
}
if plen := 1 << (first & 0x1f); plen < 512 {
t.Errorf("first packet too short: got %d want at least %d", plen, 512)
}
if err := buf.UnreadByte(); err != nil {
t.Fatal(err)
}
w.Close()
want := (maxChunkSize * (maxChunkSize + 1)) / 2
copyBuf := bytes.NewBuffer(nil)
@@ -267,25 +253,3 @@ func TestPartialLengths(t *testing.T) {
}
}
}
func TestPartialLengthsShortWrite(t *testing.T) {
buf := bytes.NewBuffer(nil)
w := &partialLengthWriter{
w: noOpCloser{buf},
}
data := bytes.Repeat([]byte("a"), 510)
if _, err := w.Write(data); err != nil {
t.Fatal(err)
}
if err := w.Close(); err != nil {
t.Fatal(err)
}
copyBuf := bytes.NewBuffer(nil)
r := &partialLengthReader{buf, 0, true}
if _, err := io.Copy(copyBuf, r); err != nil {
t.Fatal(err)
}
if !bytes.Equal(copyBuf.Bytes(), data) {
t.Errorf("got %q want %q", buf.Bytes(), data)
}
}
+1 -1
View File
@@ -31,7 +31,7 @@ type PrivateKey struct {
encryptedData []byte
cipher CipherFunction
s2k func(out, in []byte)
PrivateKey interface{} // An *{rsa|dsa|ecdsa}.PrivateKey or crypto.Signer/crypto.Decrypter (Decryptor RSA only).
PrivateKey interface{} // An *{rsa|dsa|ecdsa}.PrivateKey or a crypto.Signer.
sha1Checksum bool
iv []byte
}
-1
View File
@@ -252,7 +252,6 @@ func Decode(pfxData []byte, password string) (privateKey interface{}, certificat
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
if privateKey != nil {
err = errors.New("pkcs12: expected exactly one key bag")
return nil, nil, err
}
if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
-39
View File
@@ -1,39 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.13
package poly1305
// Generic fallbacks for the math/bits intrinsics, copied from
// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had
// variable time fallbacks until Go 1.13.
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
sum = x + y + carry
carryOut = ((x & y) | ((x | y) &^ sum)) >> 63
return
}
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
diff = x - y - borrow
borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63
return
}
func bitsMul64(x, y uint64) (hi, lo uint64) {
const mask32 = 1<<32 - 1
x0 := x & mask32
x1 := x >> 32
y0 := y & mask32
y1 := y >> 32
w0 := x0 * y0
t := x1*y0 + w0>>32
w1 := t & mask32
w2 := t >> 32
w1 += x0 * y1
hi = x1*y1 + w2 + w1>>32
lo = x * y
return
}
-21
View File
@@ -1,21 +0,0 @@
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.13
package poly1305
import "math/bits"
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
return bits.Add64(x, y, carry)
}
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
return bits.Sub64(x, y, borrow)
}
func bitsMul64(x, y uint64) (hi, lo uint64) {
return bits.Mul64(x, y)
}
+3 -1
View File
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !amd64,!ppc64le,!s390x gccgo purego
// +build !amd64,!ppc64le gccgo appengine
package poly1305
type mac struct{ macGeneric }
func newMAC(key *[32]byte) mac { return mac{newMACGeneric(key)} }
+9 -25
View File
@@ -22,16 +22,8 @@ import "crypto/subtle"
// TagSize is the size, in bytes, of a poly1305 authenticator.
const TagSize = 16
// 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 *[16]byte, m []byte, key *[32]byte) {
h := New(key)
h.Write(m)
h.Sum(out[:0])
}
// Verify returns true if mac is a valid authenticator for m with the given key.
// Verify returns true if mac is a valid authenticator for m with the given
// key.
func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
var tmp [16]byte
Sum(&tmp, m, key)
@@ -48,9 +40,10 @@ func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
// two different messages with the same key allows an attacker
// to forge messages at will.
func New(key *[32]byte) *MAC {
m := &MAC{}
initialize(key, &m.macState)
return m
return &MAC{
mac: newMAC(key),
finalized: false,
}
}
// MAC is an io.Writer computing an authentication tag
@@ -59,7 +52,7 @@ func New(key *[32]byte) *MAC {
// MAC cannot be used like common hash.Hash implementations,
// because using a poly1305 key twice breaks its security.
// Therefore writing data to a running MAC after calling
// Sum or Verify causes it to panic.
// Sum causes it to panic.
type MAC struct {
mac // platform-dependent implementation
@@ -72,10 +65,10 @@ func (h *MAC) Size() int { return TagSize }
// Write adds more data to the running message authentication code.
// It never returns an error.
//
// It must not be called after the first call of Sum or Verify.
// It must not be called after the first call of Sum.
func (h *MAC) Write(p []byte) (n int, err error) {
if h.finalized {
panic("poly1305: write to MAC after Sum or Verify")
panic("poly1305: write to MAC after Sum")
}
return h.mac.Write(p)
}
@@ -88,12 +81,3 @@ func (h *MAC) Sum(b []byte) []byte {
h.finalized = true
return append(b, mac[:]...)
}
// Verify returns whether the authenticator of all data written to
// the message authentication code matches the expected value.
func (h *MAC) Verify(expected []byte) bool {
var mac [TagSize]byte
h.mac.Sum(&mac)
h.finalized = true
return subtle.ConstantTimeCompare(expected, mac[:]) == 1
}
+8 -87
View File
@@ -5,8 +5,6 @@
package poly1305
import (
"crypto/rand"
"encoding/binary"
"encoding/hex"
"flag"
"testing"
@@ -16,10 +14,9 @@ import (
var stressFlag = flag.Bool("stress", false, "run slow stress tests")
type test struct {
in string
key string
tag string
state string
in string
key string
tag string
}
func (t *test) Input() []byte {
@@ -50,33 +47,9 @@ func (t *test) Tag() [16]byte {
return tag
}
func (t *test) InitialState() [3]uint64 {
// state is hex encoded in big-endian byte order
if t.state == "" {
return [3]uint64{0, 0, 0}
}
buf, err := hex.DecodeString(t.state)
if err != nil {
panic(err)
}
if len(buf) != 3*8 {
panic("incorrect state length")
}
return [3]uint64{
binary.BigEndian.Uint64(buf[16:24]),
binary.BigEndian.Uint64(buf[8:16]),
binary.BigEndian.Uint64(buf[0:8]),
}
}
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 {
// cannot set initial state before calling sum, so skip those tests
if v.InitialState() != [3]uint64{0, 0, 0} {
continue
}
in := v.Input()
if unaligned {
in = unalignBytes(in)
@@ -86,30 +59,6 @@ func testSum(t *testing.T, unaligned bool, sumImpl func(tag *[TagSize]byte, msg
if tag != v.Tag() {
t.Errorf("%d: expected %x, got %x", i, v.Tag(), tag[:])
}
if !Verify(&tag, in, &key) {
t.Errorf("%d: tag didn't verify", i)
}
// If the key is zero, the tag will always be zero, independent of the input.
if len(in) > 0 && key != [32]byte{} {
in[0] ^= 0xff
if Verify(&tag, in, &key) {
t.Errorf("%d: tag verified after altering the input", i)
}
in[0] ^= 0xff
}
// If the input is empty, the tag only depends on the second half of the key.
if len(in) > 0 {
key[0] ^= 0xff
if Verify(&tag, in, &key) {
t.Errorf("%d: tag verified after altering the key", i)
}
key[0] ^= 0xff
}
tag[0] ^= 0xff
if Verify(&tag, in, &key) {
t.Errorf("%d: tag verified after altering the tag", i)
}
tag[0] ^= 0xff
}
}
@@ -166,17 +115,8 @@ func testWriteGeneric(t *testing.T, unaligned bool) {
input = unalignBytes(input)
}
h := newMACGeneric(&key)
if s := v.InitialState(); s != [3]uint64{0, 0, 0} {
h.macState.h = s
}
n, err := h.Write(input[:len(input)/3])
if err != nil || n != len(input[:len(input)/3]) {
t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err)
}
n, err = h.Write(input[len(input)/3:])
if err != nil || n != len(input[len(input)/3:]) {
t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err)
}
h.Write(input[:len(input)/2])
h.Write(input[len(input)/2:])
h.Sum(&out)
if tag := v.Tag(); out != tag {
t.Errorf("%d: expected %x, got %x", i, tag[:], out[:])
@@ -194,29 +134,12 @@ func testWrite(t *testing.T, unaligned bool) {
input = unalignBytes(input)
}
h := New(&key)
if s := v.InitialState(); s != [3]uint64{0, 0, 0} {
h.macState.h = s
}
n, err := h.Write(input[:len(input)/3])
if err != nil || n != len(input[:len(input)/3]) {
t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err)
}
n, err = h.Write(input[len(input)/3:])
if err != nil || n != len(input[len(input)/3:]) {
t.Errorf("#%d: unexpected Write results: n = %d, err = %v", i, n, err)
}
h.Write(input[:len(input)/2])
h.Write(input[len(input)/2:])
h.Sum(out[:0])
tag := v.Tag()
if out != tag {
if tag := v.Tag(); out != tag {
t.Errorf("%d: expected %x, got %x", i, tag[:], out[:])
}
if !h.Verify(tag[:]) {
t.Errorf("%d: Verify failed", i)
}
tag[0] ^= 0xff
if h.Verify(tag[:]) {
t.Errorf("%d: Verify succeeded after modifying the tag", i)
}
}
}
@@ -227,7 +150,6 @@ func benchmarkSum(b *testing.B, size int, unaligned bool) {
if unaligned {
in = unalignBytes(in)
}
rand.Read(in)
b.SetBytes(int64(len(in)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
@@ -242,7 +164,6 @@ func benchmarkWrite(b *testing.B, size int, unaligned bool) {
if unaligned {
in = unalignBytes(in)
}
rand.Read(in)
b.SetBytes(int64(len(in)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
+43 -22
View File
@@ -2,46 +2,67 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !gccgo,!purego
// +build amd64,!gccgo,!appengine
package poly1305
//go:noescape
func update(state *macState, msg []byte)
func initialize(state *[7]uint64, key *[32]byte)
// mac is a wrapper for macGeneric that redirects calls that would have gone to
// updateGeneric to update.
//
// Its Write and Sum methods are otherwise identical to the macGeneric ones, but
// using function pointers would carry a major performance cost.
type mac struct{ macGeneric }
//go:noescape
func update(state *[7]uint64, msg []byte)
func (h *mac) Write(p []byte) (int, error) {
nn := len(p)
//go:noescape
func finalize(tag *[TagSize]byte, state *[7]uint64)
// Sum generates an authenticator for m using a one-time key and puts the
// 16-byte result into out. Authenticating two different messages with the same
// key allows an attacker to forge messages at will.
func Sum(out *[16]byte, m []byte, key *[32]byte) {
h := newMAC(key)
h.Write(m)
h.Sum(out)
}
func newMAC(key *[32]byte) (h mac) {
initialize(&h.state, key)
return
}
type mac struct {
state [7]uint64 // := uint64{ h0, h1, h2, r0, r1, pad0, pad1 }
buffer [TagSize]byte
offset int
}
func (h *mac) Write(p []byte) (n int, err error) {
n = len(p)
if h.offset > 0 {
n := copy(h.buffer[h.offset:], p)
if h.offset+n < TagSize {
h.offset += n
return nn, nil
remaining := TagSize - h.offset
if n < remaining {
h.offset += copy(h.buffer[h.offset:], p)
return n, nil
}
p = p[n:]
copy(h.buffer[h.offset:], p[:remaining])
p = p[remaining:]
h.offset = 0
update(&h.macState, h.buffer[:])
update(&h.state, h.buffer[:])
}
if n := len(p) - (len(p) % TagSize); n > 0 {
update(&h.macState, p[:n])
p = p[n:]
if nn := len(p) - (len(p) % TagSize); nn > 0 {
update(&h.state, p[:nn])
p = p[nn:]
}
if len(p) > 0 {
h.offset += copy(h.buffer[h.offset:], p)
}
return nn, nil
return n, nil
}
func (h *mac) Sum(out *[16]byte) {
state := h.macState
state := h.state
if h.offset > 0 {
update(&state, h.buffer[:h.offset])
}
finalize(out, &state.h, &state.s)
finalize(out, &state)
}

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