commit
412a1772a6
|
@ -0,0 +1,6 @@
|
|||
FROM alpine:latest
|
||||
RUN apk --no-cache add ca-certificates
|
||||
COPY keel /bin/keel
|
||||
ENTRYPOINT ["/bin/keel"]
|
||||
|
||||
EXPOSE 9300
|
|
@ -1,5 +1,5 @@
|
|||
hash: 8aa55088148c1c47a2b28df775d5862be1e4296dddee51154e5a1c1e782ca86e
|
||||
updated: 2017-07-21T17:52:39.653942432+01:00
|
||||
hash: 4f5cf366af304cb50b974df8ea9c020057f1d3b2bf1d1f9bd462a1e436c4f13b
|
||||
updated: 2017-08-04T22:06:13.059396344+01:00
|
||||
imports:
|
||||
- name: cloud.google.com/go
|
||||
version: b4e9a381a01e953e880e6d2cf7fd02d412977cae
|
||||
|
@ -105,11 +105,11 @@ imports:
|
|||
- name: github.com/rusenask/cron
|
||||
version: 287f34f2c2db9a9d41ec56856746cce28dd53ec5
|
||||
- name: github.com/rusenask/docker-registry-client
|
||||
version: c2590d539ef6f588fc2124c66ca94830367dbcb7
|
||||
version: 315973e9173738626b8c81cb39ba247f8cb190e5
|
||||
subpackages:
|
||||
- registry
|
||||
- name: github.com/Sirupsen/logrus
|
||||
version: 00386b3fbd637582f90cb17482dc3087646c0ac2
|
||||
version: 181d419aa9e2223811b824e8f0b4af96f9ba9302
|
||||
- name: github.com/spf13/pflag
|
||||
version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7
|
||||
- name: github.com/ugorji/go
|
||||
|
@ -119,7 +119,7 @@ imports:
|
|||
- name: github.com/urfave/negroni
|
||||
version: fde5e16d32adc7ad637e9cd9ad21d4ebc6192535
|
||||
- name: golang.org/x/crypto
|
||||
version: d172538b2cfce0c13cee31e647d0367aa8cd2486
|
||||
version: 42ff06aea7c329876e5a0fe94acc96902accf0ad
|
||||
subpackages:
|
||||
- ssh/terminal
|
||||
- name: golang.org/x/net
|
||||
|
@ -149,10 +149,12 @@ imports:
|
|||
version: 8f0908ab3b2457e2e15403d3697c9ef5cb4b57a9
|
||||
subpackages:
|
||||
- unix
|
||||
- windows
|
||||
- name: golang.org/x/text
|
||||
version: 836efe42bb4aa16aaa17b9c155d8813d336ed720
|
||||
subpackages:
|
||||
- cases
|
||||
- internal
|
||||
- internal/tag
|
||||
- language
|
||||
- runes
|
||||
|
@ -189,7 +191,7 @@ imports:
|
|||
- socket
|
||||
- urlfetch
|
||||
- name: google.golang.org/genproto
|
||||
version: b0a3dcfcd1a9bd48e63634bd8802960804cf8315
|
||||
version: 09f6ed296fc66555a25fe4ce95173148778dfa85
|
||||
subpackages:
|
||||
- googleapis/api/annotations
|
||||
- googleapis/iam/v1
|
||||
|
@ -343,7 +345,7 @@ imports:
|
|||
- util/homedir
|
||||
- util/integer
|
||||
- name: k8s.io/helm
|
||||
version: 012cb0ac1a1b2f888144ef5a67b8dab6c2d45be6
|
||||
version: 7cf31e8d9a026287041bae077b09165be247ae66
|
||||
subpackages:
|
||||
- pkg/chartutil
|
||||
- pkg/helm
|
||||
|
|
|
@ -27,6 +27,7 @@ import:
|
|||
- package: github.com/rusenask/cron
|
||||
version: v1.1.0
|
||||
- package: github.com/rusenask/docker-registry-client
|
||||
version: ^0.1.0
|
||||
subpackages:
|
||||
- registry
|
||||
- package: github.com/urfave/negroni
|
||||
|
|
|
@ -3,9 +3,9 @@ package registry
|
|||
import (
|
||||
"github.com/rusenask/keel/constants"
|
||||
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDigest(t *testing.T) {
|
||||
|
@ -29,7 +29,6 @@ func TestDigest(t *testing.T) {
|
|||
func TestGet(t *testing.T) {
|
||||
client := New()
|
||||
repo, err := client.Get(Opts{
|
||||
// Registry: "https://index.docker.io",
|
||||
Registry: constants.DefaultDockerRegistry,
|
||||
Name: "karolisr/keel",
|
||||
})
|
||||
|
@ -41,3 +40,28 @@ func TestGet(t *testing.T) {
|
|||
fmt.Println(repo.Name)
|
||||
fmt.Println(repo.Tags)
|
||||
}
|
||||
|
||||
var EnvArtifactoryUsername = "ARTIFACTORY_USERNAME"
|
||||
var EnvArtifactoryPassword = "ARTIFACTORY_PASSWORD"
|
||||
|
||||
func TestGetArtifactory(t *testing.T) {
|
||||
|
||||
if os.Getenv(EnvArtifactoryUsername) == "" && os.Getenv(EnvArtifactoryPassword) == "" {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
client := New()
|
||||
repo, err := client.Get(Opts{
|
||||
Registry: "https://keel-docker-local.jfrog.io",
|
||||
Name: "webhook-demo",
|
||||
Username: os.Getenv(EnvArtifactoryUsername),
|
||||
Password: os.Getenv(EnvArtifactoryPassword),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("error while getting repo: %s", err)
|
||||
}
|
||||
|
||||
fmt.Println(repo.Name)
|
||||
fmt.Println(repo.Tags)
|
||||
}
|
||||
|
|
|
@ -9,5 +9,7 @@ env:
|
|||
install:
|
||||
- go get github.com/stretchr/testify/assert
|
||||
- go get gopkg.in/gemnasium/logrus-airbrake-hook.v2
|
||||
- go get golang.org/x/sys/unix
|
||||
- go get golang.org/x/sys/windows
|
||||
script:
|
||||
- go test -race -v ./...
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Logrus <img src="http://i.imgur.com/hTeVwmJ.png" width="40" height="40" alt=":walrus:" class="emoji" title=":walrus:"/> [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/sirupsen/logrus?status.svg)](https://godoc.org/github.com/sirupsen/logrus)
|
||||
|
||||
Logrus is a structured logger for Go (golang), completely API compatible with
|
||||
the standard library logger. [Godoc][godoc].
|
||||
the standard library logger.
|
||||
|
||||
**Seeing weird case-sensitive problems?** It's in the past been possible to
|
||||
import Logrus as both upper- and lower-case. Due to the Go package environment,
|
||||
|
|
|
@ -2,7 +2,10 @@ package logrus
|
|||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
@ -11,30 +14,36 @@ func TestRegister(t *testing.T) {
|
|||
current := len(handlers)
|
||||
RegisterExitHandler(func() {})
|
||||
if len(handlers) != current+1 {
|
||||
t.Fatalf("can't add handler")
|
||||
t.Fatalf("expected %d handlers, got %d", current+1, len(handlers))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
gofile := "/tmp/testprog.go"
|
||||
tempDir, err := ioutil.TempDir("", "test_handler")
|
||||
if err != nil {
|
||||
log.Fatalf("can't create temp dir. %q", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
gofile := filepath.Join(tempDir, "gofile.go")
|
||||
if err := ioutil.WriteFile(gofile, testprog, 0666); err != nil {
|
||||
t.Fatalf("can't create go file")
|
||||
t.Fatalf("can't create go file. %q", err)
|
||||
}
|
||||
|
||||
outfile := "/tmp/testprog.out"
|
||||
outfile := filepath.Join(tempDir, "outfile.out")
|
||||
arg := time.Now().UTC().String()
|
||||
err := exec.Command("go", "run", gofile, outfile, arg).Run()
|
||||
err = exec.Command("go", "run", gofile, outfile, arg).Run()
|
||||
if err == nil {
|
||||
t.Fatalf("completed normally, should have failed")
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(outfile)
|
||||
if err != nil {
|
||||
t.Fatalf("can't read output file %s", outfile)
|
||||
t.Fatalf("can't read output file %s. %q", outfile, err)
|
||||
}
|
||||
|
||||
if string(data) != arg {
|
||||
t.Fatalf("bad data")
|
||||
t.Fatalf("bad data. Expected %q, got %q", data, arg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
version: "{build}"
|
||||
platform: x64
|
||||
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
install:
|
||||
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
|
||||
- go version
|
||||
build_script:
|
||||
- go get -t
|
||||
- go test
|
|
@ -2,7 +2,7 @@ package logrus
|
|||
|
||||
import "time"
|
||||
|
||||
const DefaultTimestampFormat = time.RFC3339
|
||||
const defaultTimestampFormat = time.RFC3339
|
||||
|
||||
// The Formatter interface is used to implement a custom Formatter. It takes an
|
||||
// `Entry`. It exposes all the fields, including the default ones:
|
||||
|
|
|
@ -6,8 +6,11 @@ import (
|
|||
)
|
||||
|
||||
type fieldKey string
|
||||
|
||||
// FieldMap allows customization of the key names for default fields.
|
||||
type FieldMap map[fieldKey]string
|
||||
|
||||
// Default key names for the default fields
|
||||
const (
|
||||
FieldKeyMsg = "msg"
|
||||
FieldKeyLevel = "level"
|
||||
|
@ -22,6 +25,7 @@ func (f FieldMap) resolve(key fieldKey) string {
|
|||
return string(key)
|
||||
}
|
||||
|
||||
// JSONFormatter formats logs into parsable json
|
||||
type JSONFormatter struct {
|
||||
// TimestampFormat sets the format used for marshaling timestamps.
|
||||
TimestampFormat string
|
||||
|
@ -29,7 +33,7 @@ type JSONFormatter struct {
|
|||
// DisableTimestamp allows disabling automatic timestamps in output
|
||||
DisableTimestamp bool
|
||||
|
||||
// FieldMap allows users to customize the names of keys for various fields.
|
||||
// FieldMap allows users to customize the names of keys for default fields.
|
||||
// As an example:
|
||||
// formatter := &JSONFormatter{
|
||||
// FieldMap: FieldMap{
|
||||
|
@ -41,6 +45,7 @@ type JSONFormatter struct {
|
|||
FieldMap FieldMap
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
data := make(Fields, len(entry.Data)+3)
|
||||
for k, v := range entry.Data {
|
||||
|
@ -57,7 +62,7 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
|
||||
if !f.DisableTimestamp {
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
// +build appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import "io"
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal(f io.Writer) bool {
|
||||
return true
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
const ioctlReadTermios = unix.TIOCGETA
|
||||
|
||||
type Termios syscall.Termios
|
||||
type Termios unix.Termios
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
package logrus
|
||||
|
||||
import "syscall"
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
const ioctlReadTermios = unix.TCGETS
|
||||
|
||||
type Termios syscall.Termios
|
||||
type Termios unix.Termios
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux darwin freebsd openbsd netbsd dragonfly
|
||||
// +build !appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal(f io.Writer) bool {
|
||||
var termios Termios
|
||||
switch v := f.(type) {
|
||||
case *os.File:
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(v.Fd()), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
// +build solaris,!appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(f io.Writer) bool {
|
||||
switch v := f.(type) {
|
||||
case *os.File:
|
||||
_, err := unix.IoctlGetTermios(int(v.Fd()), unix.TCGETA)
|
||||
return err == nil
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
// Based on ssh/terminal:
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows,!appengine
|
||||
|
||||
package logrus
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
var (
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
|
||||
)
|
||||
|
||||
const (
|
||||
enableProcessedOutput = 0x0001
|
||||
enableWrapAtEolOutput = 0x0002
|
||||
enableVirtualTerminalProcessing = 0x0004
|
||||
)
|
||||
|
||||
func getVersion() (float64, error) {
|
||||
stdout, stderr := &bytes.Buffer{}, &bytes.Buffer{}
|
||||
cmd := exec.Command("cmd", "ver")
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// The output should be like "Microsoft Windows [Version XX.X.XXXXXX]"
|
||||
version := strings.Replace(stdout.String(), "\n", "", -1)
|
||||
version = strings.Replace(version, "\r\n", "", -1)
|
||||
|
||||
x1 := strings.Index(version, "[Version")
|
||||
|
||||
if x1 == -1 || strings.Index(version, "]") == -1 {
|
||||
return -1, errors.New("Can't determine Windows version")
|
||||
}
|
||||
|
||||
return strconv.ParseFloat(version[x1+9:x1+13], 64)
|
||||
}
|
||||
|
||||
func init() {
|
||||
ver, err := getVersion()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Activate Virtual Processing for Windows CMD
|
||||
// Info: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||
if ver >= 10 {
|
||||
handle := syscall.Handle(os.Stderr.Fd())
|
||||
procSetConsoleMode.Call(uintptr(handle), enableProcessedOutput|enableWrapAtEolOutput|enableVirtualTerminalProcessing)
|
||||
}
|
||||
}
|
||||
|
||||
// IsTerminal returns true if stderr's file descriptor is a terminal.
|
||||
func IsTerminal(f io.Writer) bool {
|
||||
switch v := f.(type) {
|
||||
case *os.File:
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(v.Fd()), uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -3,10 +3,14 @@ package logrus
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -26,6 +30,7 @@ func init() {
|
|||
baseTimestamp = time.Now()
|
||||
}
|
||||
|
||||
// TextFormatter formats logs into text
|
||||
type TextFormatter struct {
|
||||
// Set to true to bypass checking for a TTY before outputting colors.
|
||||
ForceColors bool
|
||||
|
@ -60,10 +65,20 @@ type TextFormatter struct {
|
|||
|
||||
func (f *TextFormatter) init(entry *Entry) {
|
||||
if entry.Logger != nil {
|
||||
f.isTerminal = IsTerminal(entry.Logger.Out)
|
||||
f.isTerminal = f.checkIfTerminal(entry.Logger.Out)
|
||||
}
|
||||
}
|
||||
|
||||
func (f *TextFormatter) checkIfTerminal(w io.Writer) bool {
|
||||
switch v := w.(type) {
|
||||
case *os.File:
|
||||
return terminal.IsTerminal(int(v.Fd()))
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Format renders a single log entry
|
||||
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
||||
var b *bytes.Buffer
|
||||
keys := make([]string, 0, len(entry.Data))
|
||||
|
@ -88,7 +103,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
|
|||
|
||||
timestampFormat := f.TimestampFormat
|
||||
if timestampFormat == "" {
|
||||
timestampFormat = DefaultTimestampFormat
|
||||
timestampFormat = defaultTimestampFormat
|
||||
}
|
||||
if isColored {
|
||||
f.printColored(b, entry, keys, timestampFormat)
|
||||
|
@ -154,11 +169,12 @@ func (f *TextFormatter) needsQuoting(text string) bool {
|
|||
}
|
||||
|
||||
func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) {
|
||||
|
||||
if b.Len() > 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteString(key)
|
||||
b.WriteByte('=')
|
||||
f.appendValue(b, value)
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
|
||||
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
|
||||
|
|
|
@ -9,6 +9,25 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func TestFormatting(t *testing.T) {
|
||||
tf := &TextFormatter{DisableColors: true}
|
||||
|
||||
testCases := []struct {
|
||||
value string
|
||||
expected string
|
||||
}{
|
||||
{`foo`, "time=\"0001-01-01T00:00:00Z\" level=panic test=foo\n"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
b, _ := tf.Format(WithField("test", tc.value))
|
||||
|
||||
if string(b) != tc.expected {
|
||||
t.Errorf("formatting expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuoting(t *testing.T) {
|
||||
tf := &TextFormatter{DisableColors: true}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ func newFromTransport(registryUrl, username, password string, transport http.Rou
|
|||
}
|
||||
|
||||
if err := registry.Ping(); err != nil {
|
||||
return nil, err
|
||||
registry.Logf("registry failed ping request, error: %s", err)
|
||||
}
|
||||
|
||||
return registry, nil
|
||||
|
@ -108,13 +108,10 @@ func (r *Registry) url(pathTemplate string, args ...interface{}) string {
|
|||
|
||||
func (r *Registry) Ping() error {
|
||||
url := r.url("/v2/")
|
||||
// r.Logf("registry.ping url=%s", url)
|
||||
resp, err := r.Client.Get(url)
|
||||
if resp != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
return err
|
||||
resp.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
|
40
vendor/github.com/rusenask/docker-registry-client/registry/registry_test.go
generated
vendored
Normal file
40
vendor/github.com/rusenask/docker-registry-client/registry/registry_test.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetDigestDockerHub(t *testing.T) {
|
||||
client, err := New("https://index.docker.io", "", "")
|
||||
if err != nil {
|
||||
t.Errorf("failed to get registry, error: %s", err)
|
||||
}
|
||||
|
||||
tags, err := client.Tags("karolisr/keel")
|
||||
if err != nil {
|
||||
t.Errorf("failed to get tags, error: %s", err)
|
||||
}
|
||||
|
||||
if len(tags) == 0 {
|
||||
t.Errorf("no tags?")
|
||||
}
|
||||
}
|
||||
|
||||
// Supply authentication details to test this
|
||||
func TestGetDigestArtifactory(t *testing.T) {
|
||||
t.Skip()
|
||||
|
||||
client, err := New("https://keel-docker-local.jfrog.io", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get registry, error: %s", err)
|
||||
}
|
||||
|
||||
tags, err := client.Tags("webhook-demo")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get tags, error: %s", err)
|
||||
}
|
||||
|
||||
if len(tags) == 0 {
|
||||
t.Errorf("no tags?")
|
||||
}
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
||||
# visible at https://tip.golang.org/AUTHORS.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
||||
# visible at https://tip.golang.org/CONTRIBUTORS.
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
This repository holds supplementary Go cryptography libraries.
|
||||
|
||||
To submit changes to this repository, see http://golang.org/doc/contribute.html.
|
|
@ -0,0 +1,21 @@
|
|||
# Go Cryptography
|
||||
|
||||
This repository holds supplementary Go cryptography libraries.
|
||||
|
||||
## Download/Install
|
||||
|
||||
The easiest way to install is to run `go get -u golang.org/x/crypto/...`. You
|
||||
can also manually git clone the repository to `$GOPATH/src/golang.org/x/crypto`.
|
||||
|
||||
## Report Issues / Send Patches
|
||||
|
||||
This repository uses Gerrit for code changes. To learn how to submit changes to
|
||||
this repository, see https://golang.org/doc/contribute.html.
|
||||
|
||||
The main issue tracker for the crypto repository is located at
|
||||
https://github.com/golang/go/issues. Prefix your issue with "x/crypto:" in the
|
||||
subject line, so it is easy to find.
|
||||
|
||||
Note that contributions to the cryptography package receive additional scrutiny
|
||||
due to their sensitive nature. Patches may take longer than normal to receive
|
||||
feedback.
|
|
@ -15,6 +15,7 @@ package acme
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
|
@ -36,9 +37,6 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/net/context/ctxhttp"
|
||||
)
|
||||
|
||||
// LetsEncryptURL is the Directory endpoint of Let's Encrypt CA.
|
||||
|
@ -47,40 +45,12 @@ const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
|
|||
const (
|
||||
maxChainLen = 5 // max depth and breadth of a certificate chain
|
||||
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.
|
||||
maxNonces = 100
|
||||
)
|
||||
|
||||
// CertOption is an optional argument type for Client methods which manipulate
|
||||
// certificate data.
|
||||
type CertOption interface {
|
||||
privateCertOpt()
|
||||
}
|
||||
|
||||
// WithKey creates an option holding a private/public key pair.
|
||||
// The private part signs a certificate, and the public part represents the signee.
|
||||
func WithKey(key crypto.Signer) CertOption {
|
||||
return &certOptKey{key}
|
||||
}
|
||||
|
||||
type certOptKey struct {
|
||||
key crypto.Signer
|
||||
}
|
||||
|
||||
func (*certOptKey) privateCertOpt() {}
|
||||
|
||||
// WithTemplate creates an option for specifying a certificate template.
|
||||
// See x509.CreateCertificate for template usage details.
|
||||
//
|
||||
// In TLSSNIxChallengeCert methods, the template is also used as parent,
|
||||
// resulting in a self-signed certificate.
|
||||
// The DNSNames field of t is always overwritten for tls-sni challenge certs.
|
||||
func WithTemplate(t *x509.Certificate) CertOption {
|
||||
return (*certOptTemplate)(t)
|
||||
}
|
||||
|
||||
type certOptTemplate x509.Certificate
|
||||
|
||||
func (*certOptTemplate) privateCertOpt() {}
|
||||
|
||||
// Client is an ACME client.
|
||||
// The only required field is Key. An example of creating a client with a new key
|
||||
// is as follows:
|
||||
|
@ -108,6 +78,9 @@ type Client struct {
|
|||
|
||||
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
|
||||
}
|
||||
|
||||
// Discover performs ACME server discovery using c.DirectoryURL.
|
||||
|
@ -126,11 +99,12 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
|
|||
if dirURL == "" {
|
||||
dirURL = LetsEncryptURL
|
||||
}
|
||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, dirURL)
|
||||
res, err := c.get(ctx, dirURL)
|
||||
if err != nil {
|
||||
return Directory{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
c.addNonce(res.Header)
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return Directory{}, responseError(res)
|
||||
}
|
||||
|
@ -146,7 +120,7 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
|
|||
CAA []string `json:"caa-identities"`
|
||||
}
|
||||
}
|
||||
if json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||
if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
|
||||
return Directory{}, err
|
||||
}
|
||||
c.dir = &Directory{
|
||||
|
@ -192,7 +166,7 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
|||
req.NotAfter = now.Add(exp).Format(time.RFC3339)
|
||||
}
|
||||
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, c.dir.CertURL, req)
|
||||
res, err := c.retryPostJWS(ctx, c.Key, c.dir.CertURL, req)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
@ -201,14 +175,14 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
|||
return nil, "", responseError(res)
|
||||
}
|
||||
|
||||
curl := res.Header.Get("location") // cert permanent URL
|
||||
curl := res.Header.Get("Location") // cert permanent URL
|
||||
if res.ContentLength == 0 {
|
||||
// no cert in the body; poll until we get it
|
||||
cert, err := c.FetchCert(ctx, curl, bundle)
|
||||
return cert, curl, err
|
||||
}
|
||||
// slurp issued cert and CA chain, if requested
|
||||
cert, err := responseCert(ctx, c.HTTPClient, res, bundle)
|
||||
cert, err := c.responseCert(ctx, res, bundle)
|
||||
return cert, curl, err
|
||||
}
|
||||
|
||||
|
@ -223,18 +197,18 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
|||
// and has expected features.
|
||||
func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
|
||||
for {
|
||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
|
||||
res, err := c.get(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
if res.StatusCode == http.StatusOK {
|
||||
return responseCert(ctx, c.HTTPClient, res, bundle)
|
||||
return c.responseCert(ctx, res, bundle)
|
||||
}
|
||||
if res.StatusCode > 299 {
|
||||
return nil, responseError(res)
|
||||
}
|
||||
d := retryAfter(res.Header.Get("retry-after"), 3*time.Second)
|
||||
d := retryAfter(res.Header.Get("Retry-After"), 3*time.Second)
|
||||
select {
|
||||
case <-time.After(d):
|
||||
// retry
|
||||
|
@ -267,7 +241,7 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte,
|
|||
if key == nil {
|
||||
key = c.Key
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, key, c.dir.RevokeURL, body)
|
||||
res, err := c.retryPostJWS(ctx, key, c.dir.RevokeURL, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -355,7 +329,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
|
|||
Resource: "new-authz",
|
||||
Identifier: authzID{Type: "dns", Value: domain},
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, c.dir.AuthzURL, req)
|
||||
res, err := c.retryPostJWS(ctx, c.Key, c.dir.AuthzURL, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -379,7 +353,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
|
|||
// If a caller needs to poll an authorization until its status is final,
|
||||
// see the WaitAuthorization method.
|
||||
func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorization, error) {
|
||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
|
||||
res, err := c.get(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -406,12 +380,14 @@ func (c *Client) GetAuthorization(ctx context.Context, url string) (*Authorizati
|
|||
func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
|
||||
req := struct {
|
||||
Resource string `json:"resource"`
|
||||
Status string `json:"status"`
|
||||
Delete bool `json:"delete"`
|
||||
}{
|
||||
Resource: "authz",
|
||||
Status: "deactivated",
|
||||
Delete: true,
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req)
|
||||
res, err := c.retryPostJWS(ctx, c.Key, url, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -428,29 +404,15 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
|
|||
//
|
||||
// It returns a non-nil Authorization only if its Status is StatusValid.
|
||||
// In all other cases WaitAuthorization returns an error.
|
||||
// If the Status is StatusInvalid, the returned error is ErrAuthorizationFailed.
|
||||
// If the Status is StatusInvalid, the returned error is of type *AuthorizationError.
|
||||
func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorization, error) {
|
||||
var count int
|
||||
sleep := func(v string, inc int) error {
|
||||
count += inc
|
||||
d := backoff(count, 10*time.Second)
|
||||
d = retryAfter(v, d)
|
||||
wakeup := time.NewTimer(d)
|
||||
defer wakeup.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-wakeup.C:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
sleep := sleeper(ctx)
|
||||
for {
|
||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
|
||||
res, err := c.get(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retry := res.Header.Get("retry-after")
|
||||
retry := res.Header.Get("Retry-After")
|
||||
if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
|
||||
res.Body.Close()
|
||||
if err := sleep(retry, 1); err != nil {
|
||||
|
@ -471,7 +433,7 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
|
|||
return raw.authorization(url), nil
|
||||
}
|
||||
if raw.Status == StatusInvalid {
|
||||
return nil, ErrAuthorizationFailed
|
||||
return nil, raw.error(url)
|
||||
}
|
||||
if err := sleep(retry, 0); err != nil {
|
||||
return nil, err
|
||||
|
@ -483,7 +445,7 @@ func (c *Client) WaitAuthorization(ctx context.Context, url string) (*Authorizat
|
|||
//
|
||||
// A client typically polls a challenge status using this method.
|
||||
func (c *Client) GetChallenge(ctx context.Context, url string) (*Challenge, error) {
|
||||
res, err := ctxhttp.Get(ctx, c.HTTPClient, url)
|
||||
res, err := c.get(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -517,7 +479,7 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error
|
|||
Type: chal.Type,
|
||||
Auth: auth,
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, chal.URI, req)
|
||||
res, err := c.retryPostJWS(ctx, c.Key, chal.URI, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -650,7 +612,7 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
|||
req.Contact = acct.Contact
|
||||
req.Agreement = acct.AgreedTerms
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req)
|
||||
res, err := c.retryPostJWS(ctx, c.Key, url, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -687,7 +649,170 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
|||
}, nil
|
||||
}
|
||||
|
||||
func responseCert(ctx context.Context, client *http.Client, res *http.Response, bundle bool) ([][]byte, error) {
|
||||
// retryPostJWS will retry calls to postJWS if there is a badNonce error,
|
||||
// clearing the stored nonces after each error.
|
||||
// If the response was 4XX-5XX, then responseError is called on the body,
|
||||
// the body is closed, and the error returned.
|
||||
func (c *Client) retryPostJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
|
||||
sleep := sleeper(ctx)
|
||||
for {
|
||||
res, err := c.postJWS(ctx, key, url, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// handle errors 4XX-5XX with responseError
|
||||
if res.StatusCode >= 400 && res.StatusCode <= 599 {
|
||||
err := responseError(res)
|
||||
res.Body.Close()
|
||||
// according to spec badNonce is urn:ietf:params:acme:error:badNonce
|
||||
// however, acme servers in the wild return their version of the error
|
||||
// https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-5.4
|
||||
if ae, ok := err.(*Error); ok && strings.HasSuffix(strings.ToLower(ae.ProblemType), ":badnonce") {
|
||||
// clear any nonces that we might've stored that might now be
|
||||
// considered bad
|
||||
c.clearNonces()
|
||||
retry := res.Header.Get("Retry-After")
|
||||
if err := sleep(retry, 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
|
||||
// postJWS signs the body with the given key and POSTs it to the provided url.
|
||||
// The body argument must be JSON-serializable.
|
||||
func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
|
||||
nonce, err := c.popNonce(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := jwsEncodeJSON(body, key, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := c.post(ctx, url, "application/jose+json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.addNonce(res.Header)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// popNonce returns a nonce value previously stored with c.addNonce
|
||||
// or fetches a fresh one from the given URL.
|
||||
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
|
||||
c.noncesMu.Lock()
|
||||
defer c.noncesMu.Unlock()
|
||||
if len(c.nonces) == 0 {
|
||||
return c.fetchNonce(ctx, url)
|
||||
}
|
||||
var nonce string
|
||||
for nonce = range c.nonces {
|
||||
delete(c.nonces, nonce)
|
||||
break
|
||||
}
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
// clearNonces clears any stored nonces
|
||||
func (c *Client) clearNonces() {
|
||||
c.noncesMu.Lock()
|
||||
defer c.noncesMu.Unlock()
|
||||
c.nonces = make(map[string]struct{})
|
||||
}
|
||||
|
||||
// addNonce stores a nonce value found in h (if any) for future use.
|
||||
func (c *Client) addNonce(h http.Header) {
|
||||
v := nonceFromHeader(h)
|
||||
if v == "" {
|
||||
return
|
||||
}
|
||||
c.noncesMu.Lock()
|
||||
defer c.noncesMu.Unlock()
|
||||
if len(c.nonces) >= maxNonces {
|
||||
return
|
||||
}
|
||||
if c.nonces == nil {
|
||||
c.nonces = make(map[string]struct{})
|
||||
}
|
||||
c.nonces[v] = struct{}{}
|
||||
}
|
||||
|
||||
func (c *Client) httpClient() *http.Client {
|
||||
if c.HTTPClient != nil {
|
||||
return c.HTTPClient
|
||||
}
|
||||
return http.DefaultClient
|
||||
}
|
||||
|
||||
func (c *Client) get(ctx context.Context, urlStr string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("GET", urlStr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.do(ctx, req)
|
||||
}
|
||||
|
||||
func (c *Client) head(ctx context.Context, urlStr string) (*http.Response, error) {
|
||||
req, err := http.NewRequest("HEAD", urlStr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.do(ctx, req)
|
||||
}
|
||||
|
||||
func (c *Client) post(ctx context.Context, urlStr, contentType string, body io.Reader) (*http.Response, error) {
|
||||
req, err := http.NewRequest("POST", urlStr, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
return c.do(ctx, req)
|
||||
}
|
||||
|
||||
func (c *Client) do(ctx context.Context, req *http.Request) (*http.Response, error) {
|
||||
res, err := c.httpClient().Do(req.WithContext(ctx))
|
||||
if err != nil {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// Prefer the unadorned context error.
|
||||
// (The acme package had tests assuming this, previously from ctxhttp's
|
||||
// behavior, predating net/http supporting contexts natively)
|
||||
// TODO(bradfitz): reconsider this in the future. But for now this
|
||||
// requires no test updates.
|
||||
return nil, ctx.Err()
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *Client) fetchNonce(ctx context.Context, url string) (string, error) {
|
||||
resp, err := c.head(ctx, url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
nonce := nonceFromHeader(resp.Header)
|
||||
if nonce == "" {
|
||||
if resp.StatusCode > 299 {
|
||||
return "", responseError(resp)
|
||||
}
|
||||
return "", errors.New("acme: nonce not found")
|
||||
}
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
func nonceFromHeader(h http.Header) string {
|
||||
return h.Get("Replay-Nonce")
|
||||
}
|
||||
|
||||
func (c *Client) responseCert(ctx context.Context, res *http.Response, bundle bool) ([][]byte, error) {
|
||||
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("acme: response stream: %v", err)
|
||||
|
@ -711,7 +836,7 @@ func responseCert(ctx context.Context, client *http.Client, res *http.Response,
|
|||
return nil, errors.New("acme: rel=up link is too large")
|
||||
}
|
||||
for _, url := range up {
|
||||
cc, err := chainCert(ctx, client, url, 0)
|
||||
cc, err := c.chainCert(ctx, url, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -725,14 +850,8 @@ func responseError(resp *http.Response) error {
|
|||
// don't care if ReadAll returns an error:
|
||||
// json.Unmarshal will fail in that case anyway
|
||||
b, _ := ioutil.ReadAll(resp.Body)
|
||||
e := struct {
|
||||
Status int
|
||||
Type string
|
||||
Detail string
|
||||
}{
|
||||
Status: resp.StatusCode,
|
||||
}
|
||||
if err := json.Unmarshal(b, &e); err != nil {
|
||||
e := &wireError{Status: resp.StatusCode}
|
||||
if err := json.Unmarshal(b, e); err != nil {
|
||||
// this is not a regular error response:
|
||||
// populate detail with anything we received,
|
||||
// e.Status will already contain HTTP response code value
|
||||
|
@ -741,12 +860,7 @@ func responseError(resp *http.Response) error {
|
|||
e.Detail = resp.Status
|
||||
}
|
||||
}
|
||||
return &Error{
|
||||
StatusCode: e.Status,
|
||||
ProblemType: e.Type,
|
||||
Detail: e.Detail,
|
||||
Header: resp.Header,
|
||||
}
|
||||
return e.error(resp.Header)
|
||||
}
|
||||
|
||||
// chainCert fetches CA certificate chain recursively by following "up" links.
|
||||
|
@ -754,12 +868,12 @@ func responseError(resp *http.Response) error {
|
|||
// if the recursion level reaches maxChainLen.
|
||||
//
|
||||
// First chainCert call starts with depth of 0.
|
||||
func chainCert(ctx context.Context, client *http.Client, url string, depth int) ([][]byte, error) {
|
||||
func (c *Client) chainCert(ctx context.Context, url string, depth int) ([][]byte, error) {
|
||||
if depth >= maxChainLen {
|
||||
return nil, errors.New("acme: certificate chain is too deep")
|
||||
}
|
||||
|
||||
res, err := ctxhttp.Get(ctx, client, url)
|
||||
res, err := c.get(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -781,7 +895,7 @@ func chainCert(ctx context.Context, client *http.Client, url string, depth int)
|
|||
return nil, errors.New("acme: certificate chain is too large")
|
||||
}
|
||||
for _, up := range uplink {
|
||||
cc, err := chainCert(ctx, client, up, depth+1)
|
||||
cc, err := c.chainCert(ctx, up, depth+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -791,33 +905,6 @@ func chainCert(ctx context.Context, client *http.Client, url string, depth int)
|
|||
return chain, nil
|
||||
}
|
||||
|
||||
// postJWS signs the body with the given key and POSTs it to the provided url.
|
||||
// The body argument must be JSON-serializable.
|
||||
func postJWS(ctx context.Context, client *http.Client, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
|
||||
nonce, err := fetchNonce(ctx, client, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := jwsEncodeJSON(body, key, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ctxhttp.Post(ctx, client, url, "application/jose+json", bytes.NewReader(b))
|
||||
}
|
||||
|
||||
func fetchNonce(ctx context.Context, client *http.Client, url string) (string, error) {
|
||||
resp, err := ctxhttp.Head(ctx, client, url)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
enc := resp.Header.Get("replay-nonce")
|
||||
if enc == "" {
|
||||
return "", errors.New("acme: nonce not found")
|
||||
}
|
||||
return enc, nil
|
||||
}
|
||||
|
||||
// linkHeader returns URI-Reference values of all Link headers
|
||||
// with relation-type rel.
|
||||
// See https://tools.ietf.org/html/rfc5988#section-5 for details.
|
||||
|
@ -838,6 +925,28 @@ func linkHeader(h http.Header, rel string) []string {
|
|||
return links
|
||||
}
|
||||
|
||||
// sleeper returns a function that accepts the Retry-After HTTP header value
|
||||
// and an increment that's used with backoff to increasingly sleep on
|
||||
// consecutive calls until the context is done. If the Retry-After header
|
||||
// cannot be parsed, then backoff is used with a maximum sleep time of 10
|
||||
// seconds.
|
||||
func sleeper(ctx context.Context) func(ra string, inc int) error {
|
||||
var count int
|
||||
return func(ra string, inc int) error {
|
||||
count += inc
|
||||
d := backoff(count, 10*time.Second)
|
||||
d = retryAfter(ra, d)
|
||||
wakeup := time.NewTimer(d)
|
||||
defer wakeup.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-wakeup.C:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// retryAfter parses a Retry-After HTTP header value,
|
||||
// trying to convert v into an int (seconds) or use http.ParseTime otherwise.
|
||||
// It returns d if v cannot be parsed.
|
||||
|
@ -919,7 +1028,8 @@ func tlsChallengeCert(san []string, opt []CertOption) (tls.Certificate, error) {
|
|||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().Add(24 * time.Hour),
|
||||
BasicConstraintsValid: true,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment,
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
}
|
||||
}
|
||||
tmpl.DNSNames = san
|
||||
|
|
|
@ -6,6 +6,7 @@ package acme
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
|
@ -23,8 +24,6 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
|
||||
|
@ -45,6 +44,28 @@ func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
type jwsHead struct {
|
||||
Alg string
|
||||
Nonce string
|
||||
JWK map[string]string `json:"jwk"`
|
||||
}
|
||||
|
||||
func decodeJWSHead(r *http.Request) (*jwsHead, error) {
|
||||
var req struct{ Protected string }
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := base64.RawURLEncoding.DecodeString(req.Protected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var head jwsHead
|
||||
if err := json.Unmarshal(b, &head); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &head, nil
|
||||
}
|
||||
|
||||
func TestDiscover(t *testing.T) {
|
||||
const (
|
||||
reg = "https://example.com/acme/new-reg"
|
||||
|
@ -53,7 +74,7 @@ func TestDiscover(t *testing.T) {
|
|||
revoke = "https://example.com/acme/revoke-cert"
|
||||
)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("content-type", "application/json")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{
|
||||
"new-reg": %q,
|
||||
"new-authz": %q,
|
||||
|
@ -86,7 +107,7 @@ func TestRegister(t *testing.T) {
|
|||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "test-nonce")
|
||||
w.Header().Set("Replay-Nonce", "test-nonce")
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
|
@ -152,7 +173,7 @@ func TestUpdateReg(t *testing.T) {
|
|||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "test-nonce")
|
||||
w.Header().Set("Replay-Nonce", "test-nonce")
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
|
@ -213,7 +234,7 @@ func TestGetReg(t *testing.T) {
|
|||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "test-nonce")
|
||||
w.Header().Set("Replay-Nonce", "test-nonce")
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
|
@ -269,7 +290,7 @@ func TestGetReg(t *testing.T) {
|
|||
func TestAuthorize(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "test-nonce")
|
||||
w.Header().Set("Replay-Nonce", "test-nonce")
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
|
@ -350,7 +371,7 @@ func TestAuthorize(t *testing.T) {
|
|||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
|
||||
}
|
||||
if c.Token != "token1" {
|
||||
t.Errorf("c.Token = %q; want token1", c.Type)
|
||||
t.Errorf("c.Token = %q; want token1", c.Token)
|
||||
}
|
||||
|
||||
c = auth.Challenges[1]
|
||||
|
@ -361,7 +382,7 @@ func TestAuthorize(t *testing.T) {
|
|||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
|
||||
}
|
||||
if c.Token != "token2" {
|
||||
t.Errorf("c.Token = %q; want token2", c.Type)
|
||||
t.Errorf("c.Token = %q; want token2", c.Token)
|
||||
}
|
||||
|
||||
combs := [][]int{{0}, {1}}
|
||||
|
@ -373,7 +394,7 @@ func TestAuthorize(t *testing.T) {
|
|||
func TestAuthorizeValid(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "nonce")
|
||||
w.Header().Set("Replay-Nonce", "nonce")
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
|
@ -443,7 +464,7 @@ func TestGetAuthorization(t *testing.T) {
|
|||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
|
||||
}
|
||||
if c.Token != "token1" {
|
||||
t.Errorf("c.Token = %q; want token1", c.Type)
|
||||
t.Errorf("c.Token = %q; want token1", c.Token)
|
||||
}
|
||||
|
||||
c = auth.Challenges[1]
|
||||
|
@ -454,7 +475,7 @@ func TestGetAuthorization(t *testing.T) {
|
|||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
|
||||
}
|
||||
if c.Token != "token2" {
|
||||
t.Errorf("c.Token = %q; want token2", c.Type)
|
||||
t.Errorf("c.Token = %q; want token2", c.Token)
|
||||
}
|
||||
|
||||
combs := [][]int{{0}, {1}}
|
||||
|
@ -467,7 +488,7 @@ func TestWaitAuthorization(t *testing.T) {
|
|||
var count int
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
w.Header().Set("retry-after", "0")
|
||||
w.Header().Set("Retry-After", "0")
|
||||
if count > 1 {
|
||||
fmt.Fprintf(w, `{"status":"valid"}`)
|
||||
return
|
||||
|
@ -522,12 +543,15 @@ func TestWaitAuthorizationInvalid(t *testing.T) {
|
|||
if err == nil {
|
||||
t.Error("err is nil")
|
||||
}
|
||||
if _, ok := err.(*AuthorizationError); !ok {
|
||||
t.Errorf("err is %T; want *AuthorizationError", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitAuthorizationCancel(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("retry-after", "60")
|
||||
w.Header().Set("Retry-After", "60")
|
||||
fmt.Fprintf(w, `{"status":"pending"}`)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
@ -555,19 +579,23 @@ func TestWaitAuthorizationCancel(t *testing.T) {
|
|||
func TestRevokeAuthorization(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "nonce")
|
||||
w.Header().Set("Replay-Nonce", "nonce")
|
||||
return
|
||||
}
|
||||
switch r.URL.Path {
|
||||
case "/1":
|
||||
var req struct {
|
||||
Resource string
|
||||
Status string
|
||||
Delete bool
|
||||
}
|
||||
decodeJWSRequest(t, &req, r)
|
||||
if req.Resource != "authz" {
|
||||
t.Errorf("req.Resource = %q; want authz", req.Resource)
|
||||
}
|
||||
if req.Status != "deactivated" {
|
||||
t.Errorf("req.Status = %q; want deactivated", req.Status)
|
||||
}
|
||||
if !req.Delete {
|
||||
t.Errorf("req.Delete is false")
|
||||
}
|
||||
|
@ -617,14 +645,14 @@ func TestPollChallenge(t *testing.T) {
|
|||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", chall.URI)
|
||||
}
|
||||
if chall.Token != "token1" {
|
||||
t.Errorf("c.Token = %q; want token1", chall.Type)
|
||||
t.Errorf("c.Token = %q; want token1", chall.Token)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptChallenge(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "test-nonce")
|
||||
w.Header().Set("Replay-Nonce", "test-nonce")
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
|
@ -679,7 +707,7 @@ func TestAcceptChallenge(t *testing.T) {
|
|||
t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
|
||||
}
|
||||
if c.Token != "token1" {
|
||||
t.Errorf("c.Token = %q; want token1", c.Type)
|
||||
t.Errorf("c.Token = %q; want token1", c.Token)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -690,7 +718,7 @@ func TestNewCert(t *testing.T) {
|
|||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "test-nonce")
|
||||
w.Header().Set("Replay-Nonce", "test-nonce")
|
||||
return
|
||||
}
|
||||
if r.Method != "POST" {
|
||||
|
@ -773,7 +801,7 @@ func TestFetchCert(t *testing.T) {
|
|||
count++
|
||||
if count < 3 {
|
||||
up := fmt.Sprintf("<%s>;rel=up", ts.URL)
|
||||
w.Header().Set("link", up)
|
||||
w.Header().Set("Link", up)
|
||||
}
|
||||
w.Write([]byte{count})
|
||||
}))
|
||||
|
@ -792,7 +820,7 @@ func TestFetchCertRetry(t *testing.T) {
|
|||
var count int
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if count < 1 {
|
||||
w.Header().Set("retry-after", "0")
|
||||
w.Header().Set("Retry-After", "0")
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
count++
|
||||
return
|
||||
|
@ -812,7 +840,7 @@ 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.Header().Set("Retry-After", "0")
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
@ -839,7 +867,7 @@ func TestFetchCertDepth(t *testing.T) {
|
|||
t.Errorf("count = %d; want at most %d", count, maxChainLen+1)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
w.Header().Set("link", fmt.Sprintf("<%s>;rel=up", ts.URL))
|
||||
w.Header().Set("Link", fmt.Sprintf("<%s>;rel=up", ts.URL))
|
||||
w.Write([]byte{count})
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
@ -853,7 +881,7 @@ func TestFetchCertBreadth(t *testing.T) {
|
|||
var ts *httptest.Server
|
||||
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
for i := 0; i < maxChainLen+1; i++ {
|
||||
w.Header().Add("link", fmt.Sprintf("<%s>;rel=up", ts.URL))
|
||||
w.Header().Add("Link", fmt.Sprintf("<%s>;rel=up", ts.URL))
|
||||
}
|
||||
w.Write([]byte{1})
|
||||
}))
|
||||
|
@ -879,7 +907,7 @@ func TestFetchCertSize(t *testing.T) {
|
|||
func TestRevokeCert(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == "HEAD" {
|
||||
w.Header().Set("replay-nonce", "nonce")
|
||||
w.Header().Set("Replay-Nonce", "nonce")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -912,7 +940,30 @@ func TestRevokeCert(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestFetchNonce(t *testing.T) {
|
||||
func TestNonce_add(t *testing.T) {
|
||||
var c Client
|
||||
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||
c.addNonce(http.Header{"Replay-Nonce": {}})
|
||||
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||
|
||||
nonces := map[string]struct{}{"nonce": struct{}{}}
|
||||
if !reflect.DeepEqual(c.nonces, nonces) {
|
||||
t.Errorf("c.nonces = %q; want %q", c.nonces, nonces)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_addMax(t *testing.T) {
|
||||
c := &Client{nonces: make(map[string]struct{})}
|
||||
for i := 0; i < maxNonces; i++ {
|
||||
c.nonces[fmt.Sprintf("%d", i)] = struct{}{}
|
||||
}
|
||||
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||
if n := len(c.nonces); n != maxNonces {
|
||||
t.Errorf("len(c.nonces) = %d; want %d", n, maxNonces)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_fetch(t *testing.T) {
|
||||
tests := []struct {
|
||||
code int
|
||||
nonce string
|
||||
|
@ -926,13 +977,14 @@ func TestFetchNonce(t *testing.T) {
|
|||
if r.Method != "HEAD" {
|
||||
t.Errorf("%d: r.Method = %q; want HEAD", i, r.Method)
|
||||
}
|
||||
w.Header().Set("replay-nonce", tests[i].nonce)
|
||||
w.Header().Set("Replay-Nonce", tests[i].nonce)
|
||||
w.WriteHeader(tests[i].code)
|
||||
}))
|
||||
defer ts.Close()
|
||||
for ; i < len(tests); i++ {
|
||||
test := tests[i]
|
||||
n, err := fetchNonce(context.Background(), http.DefaultClient, ts.URL)
|
||||
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)
|
||||
}
|
||||
|
@ -945,6 +997,115 @@ func TestFetchNonce(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNonce_fetchError(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusTooManyRequests)
|
||||
}))
|
||||
defer ts.Close()
|
||||
c := &Client{}
|
||||
_, err := c.fetchNonce(context.Background(), ts.URL)
|
||||
e, ok := err.(*Error)
|
||||
if !ok {
|
||||
t.Fatalf("err is %T; want *Error", err)
|
||||
}
|
||||
if e.StatusCode != http.StatusTooManyRequests {
|
||||
t.Errorf("e.StatusCode = %d; want %d", e.StatusCode, http.StatusTooManyRequests)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_postJWS(t *testing.T) {
|
||||
var count int
|
||||
seen := make(map[string]bool)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
|
||||
if r.Method == "HEAD" {
|
||||
// We expect the client do a HEAD request
|
||||
// but only to fetch the first nonce.
|
||||
return
|
||||
}
|
||||
// Make client.Authorize happy; we're not testing its result.
|
||||
defer func() {
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(`{"status":"valid"}`))
|
||||
}()
|
||||
|
||||
head, err := decodeJWSHead(r)
|
||||
if err != nil {
|
||||
t.Errorf("decodeJWSHead: %v", err)
|
||||
return
|
||||
}
|
||||
if head.Nonce == "" {
|
||||
t.Error("head.Nonce is empty")
|
||||
return
|
||||
}
|
||||
if seen[head.Nonce] {
|
||||
t.Errorf("nonce is already used: %q", head.Nonce)
|
||||
}
|
||||
seen[head.Nonce] = true
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
|
||||
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||
t.Errorf("client.Authorize 1: %v", err)
|
||||
}
|
||||
// The second call should not generate another extra HEAD request.
|
||||
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||
t.Errorf("client.Authorize 2: %v", err)
|
||||
}
|
||||
|
||||
if count != 3 {
|
||||
t.Errorf("total requests count: %d; want 3", count)
|
||||
}
|
||||
if n := len(client.nonces); n != 1 {
|
||||
t.Errorf("len(client.nonces) = %d; want 1", n)
|
||||
}
|
||||
for k := range seen {
|
||||
if _, exist := client.nonces[k]; exist {
|
||||
t.Errorf("used nonce %q in client.nonces", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryPostJWS(t *testing.T) {
|
||||
var count int
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
w.Header().Set("Replay-Nonce", fmt.Sprintf("nonce%d", count))
|
||||
if r.Method == "HEAD" {
|
||||
// We expect the client to do 2 head requests to fetch
|
||||
// nonces, one to start and another after getting badNonce
|
||||
return
|
||||
}
|
||||
|
||||
head, err := decodeJWSHead(r)
|
||||
if err != nil {
|
||||
t.Errorf("decodeJWSHead: %v", err)
|
||||
} else if head.Nonce == "" {
|
||||
t.Error("head.Nonce is empty")
|
||||
} else if head.Nonce == "nonce1" {
|
||||
// return a badNonce error to force the call to retry
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(`{"type":"urn:ietf:params:acme:error:badNonce"}`))
|
||||
return
|
||||
}
|
||||
// Make client.Authorize happy; we're not testing its result.
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(`{"status":"valid"}`))
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
|
||||
// This call will fail with badNonce, causing a retry
|
||||
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||
t.Errorf("client.Authorize 1: %v", err)
|
||||
}
|
||||
if count != 4 {
|
||||
t.Errorf("total requests count: %d; want 4", count)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkHeader(t *testing.T) {
|
||||
h := http.Header{"Link": {
|
||||
`<https://example.com/acme/new-authz>;rel="next"`,
|
||||
|
|
|
@ -10,6 +10,7 @@ package autocert
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
|
@ -30,9 +31,14 @@ import (
|
|||
"time"
|
||||
|
||||
"golang.org/x/crypto/acme"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// 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.
|
||||
// TODO: Consider making it configurable or an exp backoff?
|
||||
var createCertRetryAfter = time.Minute
|
||||
|
||||
// pseudoRand is safe for concurrent use.
|
||||
var pseudoRand *lockedMathRand
|
||||
|
||||
|
@ -41,8 +47,9 @@ func init() {
|
|||
pseudoRand = &lockedMathRand{rnd: mathrand.New(src)}
|
||||
}
|
||||
|
||||
// AcceptTOS always returns true to indicate the acceptance of a CA Terms of Service
|
||||
// during account registration.
|
||||
// AcceptTOS is a Manager.Prompt function that always returns true to
|
||||
// indicate acceptance of the CA's Terms of Service during account
|
||||
// registration.
|
||||
func AcceptTOS(tosURL string) bool { return true }
|
||||
|
||||
// HostPolicy specifies which host names the Manager is allowed to respond to.
|
||||
|
@ -76,18 +83,6 @@ func defaultHostPolicy(context.Context, string) error {
|
|||
// It obtains and refreshes certificates automatically,
|
||||
// as well as providing them to a TLS server via tls.Config.
|
||||
//
|
||||
// A simple usage example:
|
||||
//
|
||||
// m := autocert.Manager{
|
||||
// Prompt: autocert.AcceptTOS,
|
||||
// HostPolicy: autocert.HostWhitelist("example.org"),
|
||||
// }
|
||||
// s := &http.Server{
|
||||
// Addr: ":https",
|
||||
// TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
|
||||
// }
|
||||
// s.ListenAndServeTLS("", "")
|
||||
//
|
||||
// To preserve issued certificates and improve overall performance,
|
||||
// use a cache implementation of Cache. For instance, DirCache.
|
||||
type Manager struct {
|
||||
|
@ -123,7 +118,7 @@ type Manager struct {
|
|||
// RenewBefore optionally specifies how early certificates should
|
||||
// be renewed before they expire.
|
||||
//
|
||||
// If zero, they're renewed 1 week before expiration.
|
||||
// If zero, they're renewed 30 days before expiration.
|
||||
RenewBefore time.Duration
|
||||
|
||||
// Client is used to perform low-level operations, such as account registration
|
||||
|
@ -141,6 +136,12 @@ type Manager struct {
|
|||
// If the Client's account key is already registered, Email is not used.
|
||||
Email string
|
||||
|
||||
// ForceRSA makes the Manager generate certificates with 2048-bit RSA keys.
|
||||
//
|
||||
// If false, a default is used. Currently the default
|
||||
// is EC-based keys using the P-256 curve.
|
||||
ForceRSA bool
|
||||
|
||||
clientMu sync.Mutex
|
||||
client *acme.Client // initialized by acmeClient method
|
||||
|
||||
|
@ -167,10 +168,23 @@ type Manager struct {
|
|||
// The error is propagated back to the caller of GetCertificate and is user-visible.
|
||||
// This does not affect cached certs. See HostPolicy field description for more details.
|
||||
func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
if m.Prompt == nil {
|
||||
return nil, errors.New("acme/autocert: Manager.Prompt not set")
|
||||
}
|
||||
|
||||
name := hello.ServerName
|
||||
if name == "" {
|
||||
return nil, errors.New("acme/autocert: missing server name")
|
||||
}
|
||||
if !strings.Contains(strings.Trim(name, "."), ".") {
|
||||
return nil, errors.New("acme/autocert: server name component count invalid")
|
||||
}
|
||||
if strings.ContainsAny(name, `/\`) {
|
||||
return nil, errors.New("acme/autocert: server name contains invalid character")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
// check whether this is a token cert requested for TLS-SNI challenge
|
||||
if strings.HasSuffix(name, ".acme.invalid") {
|
||||
|
@ -179,7 +193,7 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
|||
if cert := m.tokenCert[name]; cert != nil {
|
||||
return cert, nil
|
||||
}
|
||||
if cert, err := m.cacheGet(name); err == nil {
|
||||
if cert, err := m.cacheGet(ctx, name); err == nil {
|
||||
return cert, nil
|
||||
}
|
||||
// TODO: cache error results?
|
||||
|
@ -187,7 +201,8 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
|||
}
|
||||
|
||||
// regular domain
|
||||
cert, err := m.cert(name)
|
||||
name = strings.TrimSuffix(name, ".") // golang.org/issue/18114
|
||||
cert, err := m.cert(ctx, name)
|
||||
if err == nil {
|
||||
return cert, nil
|
||||
}
|
||||
|
@ -196,7 +211,6 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
|||
}
|
||||
|
||||
// first-time
|
||||
ctx := context.Background() // TODO: use a deadline?
|
||||
if err := m.hostPolicy()(ctx, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -204,14 +218,14 @@ func (m *Manager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.cachePut(name, cert)
|
||||
m.cachePut(ctx, name, cert)
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
// cert returns an existing certificate either from m.state or cache.
|
||||
// If a certificate is found in cache but not in m.state, the latter will be filled
|
||||
// with the cached value.
|
||||
func (m *Manager) cert(name string) (*tls.Certificate, error) {
|
||||
func (m *Manager) cert(ctx context.Context, name string) (*tls.Certificate, error) {
|
||||
m.stateMu.Lock()
|
||||
if s, ok := m.state[name]; ok {
|
||||
m.stateMu.Unlock()
|
||||
|
@ -220,7 +234,7 @@ func (m *Manager) cert(name string) (*tls.Certificate, error) {
|
|||
return s.tlscert()
|
||||
}
|
||||
defer m.stateMu.Unlock()
|
||||
cert, err := m.cacheGet(name)
|
||||
cert, err := m.cacheGet(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -242,12 +256,11 @@ func (m *Manager) cert(name string) (*tls.Certificate, error) {
|
|||
}
|
||||
|
||||
// cacheGet always returns a valid certificate, or an error otherwise.
|
||||
func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
|
||||
// If a cached certficate exists but is not valid, ErrCacheMiss is returned.
|
||||
func (m *Manager) cacheGet(ctx context.Context, domain string) (*tls.Certificate, error) {
|
||||
if m.Cache == nil {
|
||||
return nil, ErrCacheMiss
|
||||
}
|
||||
// TODO: might want to define a cache timeout on m
|
||||
ctx := context.Background()
|
||||
data, err := m.Cache.Get(ctx, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -256,7 +269,7 @@ func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
|
|||
// private
|
||||
priv, pub := pem.Decode(data)
|
||||
if priv == nil || !strings.Contains(priv.Type, "PRIVATE") {
|
||||
return nil, errors.New("acme/autocert: no private key found in cache")
|
||||
return nil, ErrCacheMiss
|
||||
}
|
||||
privKey, err := parsePrivateKey(priv.Bytes)
|
||||
if err != nil {
|
||||
|
@ -274,13 +287,14 @@ func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
|
|||
pubDER = append(pubDER, b.Bytes)
|
||||
}
|
||||
if len(pub) > 0 {
|
||||
return nil, errors.New("acme/autocert: invalid public key")
|
||||
// Leftover content not consumed by pem.Decode. Corrupt. Ignore.
|
||||
return nil, ErrCacheMiss
|
||||
}
|
||||
|
||||
// verify and create TLS cert
|
||||
leaf, err := validCert(domain, pubDER, privKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, ErrCacheMiss
|
||||
}
|
||||
tlscert := &tls.Certificate{
|
||||
Certificate: pubDER,
|
||||
|
@ -290,7 +304,7 @@ func (m *Manager) cacheGet(domain string) (*tls.Certificate, error) {
|
|||
return tlscert, nil
|
||||
}
|
||||
|
||||
func (m *Manager) cachePut(domain string, tlscert *tls.Certificate) error {
|
||||
func (m *Manager) cachePut(ctx context.Context, domain string, tlscert *tls.Certificate) error {
|
||||
if m.Cache == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -322,8 +336,6 @@ func (m *Manager) cachePut(domain string, tlscert *tls.Certificate) error {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: might want to define a cache timeout on m
|
||||
ctx := context.Background()
|
||||
return m.Cache.Put(ctx, domain, buf.Bytes())
|
||||
}
|
||||
|
||||
|
@ -363,6 +375,23 @@ func (m *Manager) createCert(ctx context.Context, domain string) (*tls.Certifica
|
|||
|
||||
der, leaf, err := m.authorizedCert(ctx, state.key, domain)
|
||||
if err != nil {
|
||||
// Remove the failed state after some time,
|
||||
// making the manager call createCert again on the following TLS hello.
|
||||
time.AfterFunc(createCertRetryAfter, func() {
|
||||
defer testDidRemoveState(domain)
|
||||
m.stateMu.Lock()
|
||||
defer m.stateMu.Unlock()
|
||||
// Verify the state hasn't changed and it's still invalid
|
||||
// before deleting.
|
||||
s, ok := m.state[domain]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if _, err := validCert(domain, s.cert, s.key); err == nil {
|
||||
return
|
||||
}
|
||||
delete(m.state, domain)
|
||||
})
|
||||
return nil, err
|
||||
}
|
||||
state.cert = der
|
||||
|
@ -384,11 +413,21 @@ func (m *Manager) certState(domain string) (*certState, error) {
|
|||
if state, ok := m.state[domain]; ok {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// new locked state
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
var (
|
||||
err error
|
||||
key crypto.Signer
|
||||
)
|
||||
if m.ForceRSA {
|
||||
key, err = rsa.GenerateKey(rand.Reader, 2048)
|
||||
} else {
|
||||
key, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
state := &certState{
|
||||
key: key,
|
||||
locked: true,
|
||||
|
@ -401,7 +440,6 @@ func (m *Manager) certState(domain string) (*certState, error) {
|
|||
// authorizedCert starts domain ownership verification process and requests a new cert upon success.
|
||||
// The key argument is the certificate private key.
|
||||
func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
|
||||
// TODO: make m.verify retry or retry m.verify calls here
|
||||
if err := m.verify(ctx, domain); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -477,7 +515,7 @@ func (m *Manager) verify(ctx context.Context, domain string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.putTokenCert(name, &cert)
|
||||
m.putTokenCert(ctx, name, &cert)
|
||||
defer func() {
|
||||
// verification has ended at this point
|
||||
// don't need token cert anymore
|
||||
|
@ -495,14 +533,14 @@ func (m *Manager) verify(ctx context.Context, domain string) error {
|
|||
|
||||
// putTokenCert stores the cert under the named key in both m.tokenCert map
|
||||
// and m.Cache.
|
||||
func (m *Manager) putTokenCert(name string, cert *tls.Certificate) {
|
||||
func (m *Manager) putTokenCert(ctx context.Context, name string, cert *tls.Certificate) {
|
||||
m.tokenCertMu.Lock()
|
||||
defer m.tokenCertMu.Unlock()
|
||||
if m.tokenCert == nil {
|
||||
m.tokenCert = make(map[string]*tls.Certificate)
|
||||
}
|
||||
m.tokenCert[name] = cert
|
||||
m.cachePut(name, cert)
|
||||
m.cachePut(ctx, name, cert)
|
||||
}
|
||||
|
||||
// deleteTokenCert removes the token certificate for the specified domain name
|
||||
|
@ -627,10 +665,10 @@ func (m *Manager) hostPolicy() HostPolicy {
|
|||
}
|
||||
|
||||
func (m *Manager) renewBefore() time.Duration {
|
||||
if m.RenewBefore > maxRandRenew {
|
||||
if m.RenewBefore > renewJitter {
|
||||
return m.RenewBefore
|
||||
}
|
||||
return 7 * 24 * time.Hour // 1 week
|
||||
return 720 * time.Hour // 30 days
|
||||
}
|
||||
|
||||
// certState is ready when its mutex is unlocked for reading.
|
||||
|
@ -772,5 +810,10 @@ func (r *lockedMathRand) int63n(max int64) int64 {
|
|||
return n
|
||||
}
|
||||
|
||||
// for easier testing
|
||||
var timeNow = time.Now
|
||||
// For easier testing.
|
||||
var (
|
||||
timeNow = time.Now
|
||||
|
||||
// Called when a state is removed.
|
||||
testDidRemoveState = func(domain string) {}
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package autocert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
|
@ -22,11 +23,11 @@ import (
|
|||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/acme"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var discoTmpl = template.Must(template.New("disco").Parse(`{
|
||||
|
@ -51,26 +52,44 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{
|
|||
]
|
||||
}`))
|
||||
|
||||
type memCache map[string][]byte
|
||||
type memCache struct {
|
||||
mu sync.Mutex
|
||||
keyData map[string][]byte
|
||||
}
|
||||
|
||||
func (m memCache) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
v, ok := m[key]
|
||||
func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
v, ok := m.keyData[key]
|
||||
if !ok {
|
||||
return nil, ErrCacheMiss
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (m memCache) Put(ctx context.Context, key string, data []byte) error {
|
||||
m[key] = data
|
||||
func (m *memCache) Put(ctx context.Context, key string, data []byte) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
m.keyData[key] = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m memCache) Delete(ctx context.Context, key string) error {
|
||||
delete(m, key)
|
||||
func (m *memCache) Delete(ctx context.Context, key string) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
delete(m.keyData, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMemCache() *memCache {
|
||||
return &memCache{
|
||||
keyData: make(map[string][]byte),
|
||||
}
|
||||
}
|
||||
|
||||
func dummyCert(pub interface{}, san ...string) ([]byte, error) {
|
||||
return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
|
||||
}
|
||||
|
@ -108,10 +127,142 @@ func decodePayload(v interface{}, r io.Reader) error {
|
|||
}
|
||||
|
||||
func TestGetCertificate(t *testing.T) {
|
||||
const domain = "example.org"
|
||||
man := &Manager{Prompt: AcceptTOS}
|
||||
defer man.stopRenew()
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||
testGetCertificate(t, man, "example.org", hello)
|
||||
}
|
||||
|
||||
func TestGetCertificate_trailingDot(t *testing.T) {
|
||||
man := &Manager{Prompt: AcceptTOS}
|
||||
defer man.stopRenew()
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org."}
|
||||
testGetCertificate(t, man, "example.org", hello)
|
||||
}
|
||||
|
||||
func TestGetCertificate_ForceRSA(t *testing.T) {
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Cache: newMemCache(),
|
||||
ForceRSA: true,
|
||||
}
|
||||
defer man.stopRenew()
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||
testGetCertificate(t, man, "example.org", hello)
|
||||
|
||||
cert, err := man.cacheGet(context.Background(), "example.org")
|
||||
if err != nil {
|
||||
t.Fatalf("man.cacheGet: %v", err)
|
||||
}
|
||||
if _, ok := cert.PrivateKey.(*rsa.PrivateKey); !ok {
|
||||
t.Errorf("cert.PrivateKey is %T; want *rsa.PrivateKey", cert.PrivateKey)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCertificate_nilPrompt(t *testing.T) {
|
||||
man := &Manager{}
|
||||
defer man.stopRenew()
|
||||
url, finish := startACMEServerStub(t, man, "example.org")
|
||||
defer finish()
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
man.Client = &acme.Client{
|
||||
Key: key,
|
||||
DirectoryURL: url,
|
||||
}
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||
if _, err := man.GetCertificate(hello); err == nil {
|
||||
t.Error("got certificate for example.org; wanted error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCertificate_expiredCache(t *testing.T) {
|
||||
// Make an expired cert and cache it.
|
||||
pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tmpl := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
Subject: pkix.Name{CommonName: "example.org"},
|
||||
NotAfter: time.Now(),
|
||||
}
|
||||
pub, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &pk.PublicKey, pk)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tlscert := &tls.Certificate{
|
||||
Certificate: [][]byte{pub},
|
||||
PrivateKey: pk,
|
||||
}
|
||||
|
||||
man := &Manager{Prompt: AcceptTOS, Cache: newMemCache()}
|
||||
defer man.stopRenew()
|
||||
if err := man.cachePut(context.Background(), "example.org", tlscert); err != nil {
|
||||
t.Fatalf("man.cachePut: %v", err)
|
||||
}
|
||||
|
||||
// The expired cached cert should trigger a new cert issuance
|
||||
// and return without an error.
|
||||
hello := &tls.ClientHelloInfo{ServerName: "example.org"}
|
||||
testGetCertificate(t, man, "example.org", hello)
|
||||
}
|
||||
|
||||
func TestGetCertificate_failedAttempt(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
const example = "example.org"
|
||||
d := createCertRetryAfter
|
||||
f := testDidRemoveState
|
||||
defer func() {
|
||||
createCertRetryAfter = d
|
||||
testDidRemoveState = f
|
||||
}()
|
||||
createCertRetryAfter = 0
|
||||
done := make(chan struct{})
|
||||
testDidRemoveState = func(domain string) {
|
||||
if domain != example {
|
||||
t.Errorf("testDidRemoveState: domain = %q; want %q", domain, example)
|
||||
}
|
||||
close(done)
|
||||
}
|
||||
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Client: &acme.Client{
|
||||
Key: key,
|
||||
DirectoryURL: ts.URL,
|
||||
},
|
||||
}
|
||||
defer man.stopRenew()
|
||||
hello := &tls.ClientHelloInfo{ServerName: example}
|
||||
if _, err := man.GetCertificate(hello); err == nil {
|
||||
t.Error("GetCertificate: err is nil")
|
||||
}
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Errorf("took too long to remove the %q state", example)
|
||||
case <-done:
|
||||
man.stateMu.Lock()
|
||||
defer man.stateMu.Unlock()
|
||||
if v, exist := man.state[example]; exist {
|
||||
t.Errorf("state exists for %q: %+v", example, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// startACMEServerStub runs an ACME server
|
||||
// The domain argument is the expected domain name of a certificate request.
|
||||
func startACMEServerStub(t *testing.T, man *Manager, domain string) (url string, finish func()) {
|
||||
// echo token-02 | shasum -a 256
|
||||
// then divide result in 2 parts separated by dot
|
||||
tokenCertName := "4e8eb87631187e9ff2153b56b13a4dec.13a35d002e485d60ff37354b32f665d9.token.acme.invalid"
|
||||
|
@ -127,7 +278,7 @@ func TestGetCertificate(t *testing.T) {
|
|||
// ACME CA server stub
|
||||
var ca *httptest.Server
|
||||
ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("replay-nonce", "nonce")
|
||||
w.Header().Set("Replay-Nonce", "nonce")
|
||||
if r.Method == "HEAD" {
|
||||
// a nonce request
|
||||
return
|
||||
|
@ -137,17 +288,17 @@ func TestGetCertificate(t *testing.T) {
|
|||
// discovery
|
||||
case "/":
|
||||
if err := discoTmpl.Execute(w, ca.URL); err != nil {
|
||||
t.Fatalf("discoTmpl: %v", err)
|
||||
t.Errorf("discoTmpl: %v", err)
|
||||
}
|
||||
// client key registration
|
||||
case "/new-reg":
|
||||
w.Write([]byte("{}"))
|
||||
// domain authorization
|
||||
case "/new-authz":
|
||||
w.Header().Set("location", ca.URL+"/authz/1")
|
||||
w.Header().Set("Location", ca.URL+"/authz/1")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
if err := authzTmpl.Execute(w, ca.URL); err != nil {
|
||||
t.Fatalf("authzTmpl: %v", err)
|
||||
t.Errorf("authzTmpl: %v", err)
|
||||
}
|
||||
// accept tls-sni-02 challenge
|
||||
case "/challenge/2":
|
||||
|
@ -165,28 +316,68 @@ func TestGetCertificate(t *testing.T) {
|
|||
b, _ := base64.RawURLEncoding.DecodeString(req.CSR)
|
||||
csr, err := x509.ParseCertificateRequest(b)
|
||||
if err != nil {
|
||||
t.Fatalf("new-cert: CSR: %v", err)
|
||||
t.Errorf("new-cert: CSR: %v", err)
|
||||
}
|
||||
if csr.Subject.CommonName != domain {
|
||||
t.Errorf("CommonName in CSR = %q; want %q", csr.Subject.CommonName, domain)
|
||||
}
|
||||
der, err := dummyCert(csr.PublicKey, domain)
|
||||
if err != nil {
|
||||
t.Fatalf("new-cert: dummyCert: %v", err)
|
||||
t.Errorf("new-cert: dummyCert: %v", err)
|
||||
}
|
||||
chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
|
||||
w.Header().Set("link", chainUp)
|
||||
w.Header().Set("Link", chainUp)
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write(der)
|
||||
// CA chain cert
|
||||
case "/ca-cert":
|
||||
der, err := dummyCert(nil, "ca")
|
||||
if err != nil {
|
||||
t.Fatalf("ca-cert: dummyCert: %v", err)
|
||||
t.Errorf("ca-cert: dummyCert: %v", err)
|
||||
}
|
||||
w.Write(der)
|
||||
default:
|
||||
t.Errorf("unrecognized r.URL.Path: %s", r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer ca.Close()
|
||||
finish = func() {
|
||||
ca.Close()
|
||||
|
||||
// make sure token cert was removed
|
||||
cancel := make(chan struct{})
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
tick := time.NewTicker(100 * time.Millisecond)
|
||||
defer tick.Stop()
|
||||
for {
|
||||
hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
|
||||
if _, err := man.GetCertificate(hello); err != nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-tick.C:
|
||||
case <-cancel:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(5 * time.Second):
|
||||
close(cancel)
|
||||
t.Error("token cert was not removed")
|
||||
<-done
|
||||
}
|
||||
}
|
||||
return ca.URL, finish
|
||||
}
|
||||
|
||||
// tests man.GetCertificate flow using the provided hello argument.
|
||||
// The domain argument is the expected domain name of a certificate request.
|
||||
func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.ClientHelloInfo) {
|
||||
url, finish := startACMEServerStub(t, man, domain)
|
||||
defer finish()
|
||||
|
||||
// use EC key to run faster on 386
|
||||
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
|
@ -195,14 +386,13 @@ func TestGetCertificate(t *testing.T) {
|
|||
}
|
||||
man.Client = &acme.Client{
|
||||
Key: key,
|
||||
DirectoryURL: ca.URL,
|
||||
DirectoryURL: url,
|
||||
}
|
||||
|
||||
// simulate tls.Config.GetCertificate
|
||||
var tlscert *tls.Certificate
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
hello := &tls.ClientHelloInfo{ServerName: domain}
|
||||
tlscert, err = man.GetCertificate(hello)
|
||||
close(done)
|
||||
}()
|
||||
|
@ -227,28 +417,10 @@ func TestGetCertificate(t *testing.T) {
|
|||
t.Errorf("cert.DNSNames = %v; want %q", cert.DNSNames, domain)
|
||||
}
|
||||
|
||||
// make sure token cert was removed
|
||||
done = make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
hello := &tls.ClientHelloInfo{ServerName: tokenCertName}
|
||||
if _, err := man.GetCertificate(hello); err != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Error("token cert was not removed")
|
||||
case <-done:
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountKeyCache(t *testing.T) {
|
||||
cache := make(memCache)
|
||||
m := Manager{Cache: cache}
|
||||
m := Manager{Cache: newMemCache()}
|
||||
ctx := context.Background()
|
||||
k1, err := m.accountKey(ctx)
|
||||
if err != nil {
|
||||
|
@ -282,13 +454,13 @@ func TestCache(t *testing.T) {
|
|||
PrivateKey: privKey,
|
||||
}
|
||||
|
||||
cache := make(memCache)
|
||||
man := &Manager{Cache: cache}
|
||||
man := &Manager{Cache: newMemCache()}
|
||||
defer man.stopRenew()
|
||||
if err := man.cachePut("example.org", tlscert); err != nil {
|
||||
ctx := context.Background()
|
||||
if err := man.cachePut(ctx, "example.org", tlscert); err != nil {
|
||||
t.Fatalf("man.cachePut: %v", err)
|
||||
}
|
||||
res, err := man.cacheGet("example.org")
|
||||
res, err := man.cacheGet(ctx, "example.org")
|
||||
if err != nil {
|
||||
t.Fatalf("man.cacheGet: %v", err)
|
||||
}
|
||||
|
@ -388,3 +560,47 @@ func TestValidCert(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
type cacheGetFunc func(ctx context.Context, key string) ([]byte, error)
|
||||
|
||||
func (f cacheGetFunc) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
return f(ctx, key)
|
||||
}
|
||||
|
||||
func (f cacheGetFunc) Put(ctx context.Context, key string, data []byte) error {
|
||||
return fmt.Errorf("unsupported Put of %q = %q", key, data)
|
||||
}
|
||||
|
||||
func (f cacheGetFunc) Delete(ctx context.Context, key string) error {
|
||||
return fmt.Errorf("unsupported Delete of %q", key)
|
||||
}
|
||||
|
||||
func TestManagerGetCertificateBogusSNI(t *testing.T) {
|
||||
m := Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Cache: cacheGetFunc(func(ctx context.Context, key string) ([]byte, error) {
|
||||
return nil, fmt.Errorf("cache.Get of %s", key)
|
||||
}),
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
wantErr string
|
||||
}{
|
||||
{"foo.com", "cache.Get of foo.com"},
|
||||
{"foo.com.", "cache.Get of foo.com"},
|
||||
{`a\b.com`, "acme/autocert: server name contains invalid character"},
|
||||
{`a/b.com`, "acme/autocert: server name contains invalid character"},
|
||||
{"", "acme/autocert: missing server name"},
|
||||
{"foo", "acme/autocert: server name component count invalid"},
|
||||
{".foo", "acme/autocert: server name component count invalid"},
|
||||
{"foo.", "acme/autocert: server name component count invalid"},
|
||||
{"fo.o", "cache.Get of fo.o"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
_, err := m.GetCertificate(&tls.ClientHelloInfo{ServerName: tt.name})
|
||||
got := fmt.Sprint(err)
|
||||
if got != tt.wantErr {
|
||||
t.Errorf("GetCertificate(SNI = %q) = %q; want %q", tt.name, got, tt.wantErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,11 @@
|
|||
package autocert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// ErrCacheMiss is returned when a certificate is not found in cache.
|
||||
|
@ -27,7 +26,7 @@ type Cache interface {
|
|||
Get(ctx context.Context, key string) ([]byte, error)
|
||||
|
||||
// Put stores the data in the cache under the specified key.
|
||||
// Inderlying implementations may use any data storage format,
|
||||
// Underlying implementations may use any data storage format,
|
||||
// as long as the reverse operation, Get, results in the original data.
|
||||
Put(ctx context.Context, key string, data []byte) error
|
||||
|
||||
|
@ -78,12 +77,13 @@ func (d DirCache) Put(ctx context.Context, name string, data []byte) error {
|
|||
if tmp, err = d.writeTempFile(name, data); err != nil {
|
||||
return
|
||||
}
|
||||
// prevent overwriting the file if the context was cancelled
|
||||
if ctx.Err() != nil {
|
||||
return // no need to set err
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// Don't overwrite the file if the context was canceled.
|
||||
default:
|
||||
newName := filepath.Join(string(d), name)
|
||||
err = os.Rename(tmp, newName)
|
||||
}
|
||||
name = filepath.Join(string(d), name)
|
||||
err = os.Rename(tmp, name)
|
||||
}()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
package autocert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// make sure DirCache satisfies Cache interface
|
||||
|
@ -22,6 +21,7 @@ func TestDirCache(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
dir = filepath.Join(dir, "certs") // a nonexistent dir
|
||||
cache := DirCache(dir)
|
||||
ctx := context.Background()
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package autocert_test
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
func ExampleNewListener() {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello, TLS user! Your config: %+v", r.TLS)
|
||||
})
|
||||
log.Fatal(http.Serve(autocert.NewListener("example.com"), mux))
|
||||
}
|
||||
|
||||
func ExampleManager() {
|
||||
m := autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
HostPolicy: autocert.HostWhitelist("example.org"),
|
||||
}
|
||||
s := &http.Server{
|
||||
Addr: ":https",
|
||||
TLSConfig: &tls.Config{GetCertificate: m.GetCertificate},
|
||||
}
|
||||
s.ListenAndServeTLS("", "")
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package autocert
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NewListener returns a net.Listener that listens on the standard TLS
|
||||
// port (443) on all interfaces and returns *tls.Conn connections with
|
||||
// LetsEncrypt certificates for the provided domain or domains.
|
||||
//
|
||||
// It enables one-line HTTPS servers:
|
||||
//
|
||||
// log.Fatal(http.Serve(autocert.NewListener("example.com"), handler))
|
||||
//
|
||||
// NewListener is a convenience function for a common configuration.
|
||||
// More complex or custom configurations can use the autocert.Manager
|
||||
// type instead.
|
||||
//
|
||||
// Use of this function implies acceptance of the LetsEncrypt Terms of
|
||||
// Service. If domains is not empty, the provided domains are passed
|
||||
// to HostWhitelist. If domains is empty, the listener will do
|
||||
// LetsEncrypt challenges for any requested domain, which is not
|
||||
// recommended.
|
||||
//
|
||||
// Certificates are cached in a "golang-autocert" directory under an
|
||||
// operating system-specific cache or temp directory. This may not
|
||||
// be suitable for servers spanning multiple machines.
|
||||
//
|
||||
// The returned listener uses a *tls.Config that enables HTTP/2, and
|
||||
// should only be used with servers that support HTTP/2.
|
||||
//
|
||||
// The returned Listener also enables TCP keep-alives on the accepted
|
||||
// connections. The returned *tls.Conn are returned before their TLS
|
||||
// handshake has completed.
|
||||
func NewListener(domains ...string) net.Listener {
|
||||
m := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
}
|
||||
if len(domains) > 0 {
|
||||
m.HostPolicy = HostWhitelist(domains...)
|
||||
}
|
||||
dir := cacheDir()
|
||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||
log.Printf("warning: autocert.NewListener not using a cache: %v", err)
|
||||
} else {
|
||||
m.Cache = DirCache(dir)
|
||||
}
|
||||
return m.Listener()
|
||||
}
|
||||
|
||||
// Listener listens on the standard TLS port (443) on all interfaces
|
||||
// and returns a net.Listener returning *tls.Conn connections.
|
||||
//
|
||||
// The returned listener uses a *tls.Config that enables HTTP/2, and
|
||||
// should only be used with servers that support HTTP/2.
|
||||
//
|
||||
// The returned Listener also enables TCP keep-alives on the accepted
|
||||
// connections. The returned *tls.Conn are returned before their TLS
|
||||
// handshake has completed.
|
||||
//
|
||||
// Unlike NewListener, it is the caller's responsibility to initialize
|
||||
// the Manager m's Prompt, Cache, HostPolicy, and other desired options.
|
||||
func (m *Manager) Listener() net.Listener {
|
||||
ln := &listener{
|
||||
m: m,
|
||||
conf: &tls.Config{
|
||||
GetCertificate: m.GetCertificate, // bonus: panic on nil m
|
||||
NextProtos: []string{"h2", "http/1.1"}, // Enable HTTP/2
|
||||
},
|
||||
}
|
||||
ln.tcpListener, ln.tcpListenErr = net.Listen("tcp", ":443")
|
||||
return ln
|
||||
}
|
||||
|
||||
type listener struct {
|
||||
m *Manager
|
||||
conf *tls.Config
|
||||
|
||||
tcpListener net.Listener
|
||||
tcpListenErr error
|
||||
}
|
||||
|
||||
func (ln *listener) Accept() (net.Conn, error) {
|
||||
if ln.tcpListenErr != nil {
|
||||
return nil, ln.tcpListenErr
|
||||
}
|
||||
conn, err := ln.tcpListener.Accept()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tcpConn := conn.(*net.TCPConn)
|
||||
|
||||
// Because Listener is a convenience function, help out with
|
||||
// this too. This is not possible for the caller to set once
|
||||
// we return a *tcp.Conn wrapping an inaccessible net.Conn.
|
||||
// If callers don't want this, they can do things the manual
|
||||
// way and tweak as needed. But this is what net/http does
|
||||
// itself, so copy that. If net/http changes, we can change
|
||||
// here too.
|
||||
tcpConn.SetKeepAlive(true)
|
||||
tcpConn.SetKeepAlivePeriod(3 * time.Minute)
|
||||
|
||||
return tls.Server(tcpConn, ln.conf), nil
|
||||
}
|
||||
|
||||
func (ln *listener) Addr() net.Addr {
|
||||
if ln.tcpListener != nil {
|
||||
return ln.tcpListener.Addr()
|
||||
}
|
||||
// net.Listen failed. Return something non-nil in case callers
|
||||
// call Addr before Accept:
|
||||
return &net.TCPAddr{IP: net.IP{0, 0, 0, 0}, Port: 443}
|
||||
}
|
||||
|
||||
func (ln *listener) Close() error {
|
||||
if ln.tcpListenErr != nil {
|
||||
return ln.tcpListenErr
|
||||
}
|
||||
return ln.tcpListener.Close()
|
||||
}
|
||||
|
||||
func homeDir() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||
}
|
||||
if h := os.Getenv("HOME"); h != "" {
|
||||
return h
|
||||
}
|
||||
return "/"
|
||||
}
|
||||
|
||||
func cacheDir() string {
|
||||
const base = "golang-autocert"
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
return filepath.Join(homeDir(), "Library", "Caches", base)
|
||||
case "windows":
|
||||
for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
|
||||
if v := os.Getenv(ev); v != "" {
|
||||
return filepath.Join(v, base)
|
||||
}
|
||||
}
|
||||
// Worst case:
|
||||
return filepath.Join(homeDir(), base)
|
||||
}
|
||||
if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
|
||||
return filepath.Join(xdg, base)
|
||||
}
|
||||
return filepath.Join(homeDir(), ".cache", base)
|
||||
}
|
|
@ -5,15 +5,14 @@
|
|||
package autocert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// maxRandRenew is a maximum deviation from Manager.RenewBefore.
|
||||
const maxRandRenew = time.Hour
|
||||
// renewJitter is the maximum deviation from Manager.RenewBefore.
|
||||
const renewJitter = time.Hour
|
||||
|
||||
// domainRenewal tracks the state used by the periodic timers
|
||||
// renewing a single domain's cert.
|
||||
|
@ -65,7 +64,7 @@ func (dr *domainRenewal) renew() {
|
|||
// TODO: rotate dr.key at some point?
|
||||
next, err := dr.do(ctx)
|
||||
if err != nil {
|
||||
next = maxRandRenew / 2
|
||||
next = renewJitter / 2
|
||||
next += time.Duration(pseudoRand.int63n(int64(next)))
|
||||
}
|
||||
dr.timer = time.AfterFunc(next, dr.renew)
|
||||
|
@ -83,9 +82,9 @@ func (dr *domainRenewal) renew() {
|
|||
func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
||||
// a race is likely unavoidable in a distributed environment
|
||||
// but we try nonetheless
|
||||
if tlscert, err := dr.m.cacheGet(dr.domain); err == nil {
|
||||
if tlscert, err := dr.m.cacheGet(ctx, dr.domain); err == nil {
|
||||
next := dr.next(tlscert.Leaf.NotAfter)
|
||||
if next > dr.m.renewBefore()+maxRandRenew {
|
||||
if next > dr.m.renewBefore()+renewJitter {
|
||||
return next, nil
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +102,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dr.m.cachePut(dr.domain, tlscert)
|
||||
dr.m.cachePut(ctx, dr.domain, tlscert)
|
||||
dr.m.stateMu.Lock()
|
||||
defer dr.m.stateMu.Unlock()
|
||||
// m.state is guaranteed to be non-nil at this point
|
||||
|
@ -114,7 +113,7 @@ func (dr *domainRenewal) do(ctx context.Context) (time.Duration, error) {
|
|||
func (dr *domainRenewal) next(expiry time.Time) time.Duration {
|
||||
d := expiry.Sub(timeNow()) - dr.m.renewBefore()
|
||||
// add a bit of randomness to renew deadline
|
||||
n := pseudoRand.int63n(int64(maxRandRenew))
|
||||
n := pseudoRand.int63n(int64(renewJitter))
|
||||
d -= time.Duration(n)
|
||||
if d < 0 {
|
||||
return 0
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package autocert
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
|
@ -31,7 +32,7 @@ func TestRenewalNext(t *testing.T) {
|
|||
expiry time.Time
|
||||
min, max time.Duration
|
||||
}{
|
||||
{now.Add(90 * 24 * time.Hour), 83*24*time.Hour - maxRandRenew, 83 * 24 * time.Hour},
|
||||
{now.Add(90 * 24 * time.Hour), 83*24*time.Hour - renewJitter, 83 * 24 * time.Hour},
|
||||
{now.Add(time.Hour), 0, 1},
|
||||
{now, 0, 1},
|
||||
{now.Add(-time.Hour), 0, 1},
|
||||
|
@ -52,7 +53,7 @@ func TestRenewFromCache(t *testing.T) {
|
|||
// ACME CA server stub
|
||||
var ca *httptest.Server
|
||||
ca = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("replay-nonce", "nonce")
|
||||
w.Header().Set("Replay-Nonce", "nonce")
|
||||
if r.Method == "HEAD" {
|
||||
// a nonce request
|
||||
return
|
||||
|
@ -69,7 +70,7 @@ func TestRenewFromCache(t *testing.T) {
|
|||
w.Write([]byte("{}"))
|
||||
// domain authorization
|
||||
case "/new-authz":
|
||||
w.Header().Set("location", ca.URL+"/authz/1")
|
||||
w.Header().Set("Location", ca.URL+"/authz/1")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(`{"status": "valid"}`))
|
||||
// cert request
|
||||
|
@ -88,7 +89,7 @@ func TestRenewFromCache(t *testing.T) {
|
|||
t.Fatalf("new-cert: dummyCert: %v", err)
|
||||
}
|
||||
chainUp := fmt.Sprintf("<%s/ca-cert>; rel=up", ca.URL)
|
||||
w.Header().Set("link", chainUp)
|
||||
w.Header().Set("Link", chainUp)
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write(der)
|
||||
// CA chain cert
|
||||
|
@ -111,7 +112,7 @@ func TestRenewFromCache(t *testing.T) {
|
|||
}
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Cache: make(memCache),
|
||||
Cache: newMemCache(),
|
||||
RenewBefore: 24 * time.Hour,
|
||||
Client: &acme.Client{
|
||||
Key: key,
|
||||
|
@ -127,7 +128,7 @@ func TestRenewFromCache(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
tlscert := &tls.Certificate{PrivateKey: key, Certificate: [][]byte{cert}}
|
||||
if err := man.cachePut(domain, tlscert); err != nil {
|
||||
if err := man.cachePut(context.Background(), domain, tlscert); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -151,7 +152,7 @@ func TestRenewFromCache(t *testing.T) {
|
|||
|
||||
// ensure the new cert is cached
|
||||
after := time.Now().Add(future)
|
||||
tlscert, err := man.cacheGet(domain)
|
||||
tlscert, err := man.cacheGet(context.Background(), domain)
|
||||
if err != nil {
|
||||
t.Fatalf("man.cacheGet: %v", err)
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ func jwsHasher(key crypto.Signer) (string, crypto.Hash) {
|
|||
return "ES256", crypto.SHA256
|
||||
case "P-384":
|
||||
return "ES384", crypto.SHA384
|
||||
case "P-512":
|
||||
case "P-521":
|
||||
return "ES512", crypto.SHA512
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,13 @@ import (
|
|||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const testKeyPEM = `
|
||||
const (
|
||||
testKeyPEM = `
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
|
||||
WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
|
||||
|
@ -46,10 +48,9 @@ EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO
|
|||
-----END RSA PRIVATE KEY-----
|
||||
`
|
||||
|
||||
// This thumbprint is for the testKey defined above.
|
||||
const testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
|
||||
// This thumbprint is for the testKey defined above.
|
||||
testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
|
||||
|
||||
const (
|
||||
// openssl ecparam -name secp256k1 -genkey -noout
|
||||
testKeyECPEM = `
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
|
@ -58,39 +59,78 @@ AwEHoUQDQgAE5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HThqIrvawF5
|
|||
QAaS/RNouybCiRhRjI3EaxLkQwgrCw0gqQ==
|
||||
-----END EC PRIVATE KEY-----
|
||||
`
|
||||
// 1. opnessl ec -in key.pem -noout -text
|
||||
// openssl ecparam -name secp384r1 -genkey -noout
|
||||
testKeyEC384PEM = `
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIGkAgEBBDAQ4lNtXRORWr1bgKR1CGysr9AJ9SyEk4jiVnlUWWUChmSNL+i9SLSD
|
||||
Oe/naPqXJ6CgBwYFK4EEACKhZANiAAQzKtj+Ms0vHoTX5dzv3/L5YMXOWuI5UKRj
|
||||
JigpahYCqXD2BA1j0E/2xt5vlPf+gm0PL+UHSQsCokGnIGuaHCsJAp3ry0gHQEke
|
||||
WYXapUUFdvaK1R2/2hn5O+eiQM8YzCg=
|
||||
-----END EC PRIVATE KEY-----
|
||||
`
|
||||
// openssl ecparam -name secp521r1 -genkey -noout
|
||||
testKeyEC512PEM = `
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MIHcAgEBBEIBSNZKFcWzXzB/aJClAb305ibalKgtDA7+70eEkdPt28/3LZMM935Z
|
||||
KqYHh/COcxuu3Kt8azRAUz3gyr4zZKhlKUSgBwYFK4EEACOhgYkDgYYABAHUNKbx
|
||||
7JwC7H6pa2sV0tERWhHhB3JmW+OP6SUgMWryvIKajlx73eS24dy4QPGrWO9/ABsD
|
||||
FqcRSkNVTXnIv6+0mAF25knqIBIg5Q8M9BnOu9GGAchcwt3O7RDHmqewnJJDrbjd
|
||||
GGnm6rb+NnWR9DIopM0nKNkToWoF/hzopxu4Ae/GsQ==
|
||||
-----END EC PRIVATE KEY-----
|
||||
`
|
||||
// 1. openssl ec -in key.pem -noout -text
|
||||
// 2. remove first byte, 04 (the header); the rest is X and Y
|
||||
// 3. covert each with: echo <val> | xxd -r -p | base64 | tr -d '=' | tr '/+' '_-'
|
||||
testKeyECPubX = "5lhEug5xK4xBDZ2nAbaxLtaLiv85bxJ7ePd1dkO23HQ"
|
||||
testKeyECPubY = "4aiK72sBeUAGkv0TaLsmwokYUYyNxGsS5EMIKwsNIKk"
|
||||
// 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"
|
||||
testKeyEC384PubY = "Dy_lB0kLAqJBpyBrmhwrCQKd68tIB0BJHlmF2qVFBXb2itUdv9oZ-TvnokDPGMwo"
|
||||
testKeyEC512PubX = "AdQ0pvHsnALsfqlraxXS0RFaEeEHcmZb44_pJSAxavK8gpqOXHvd5Lbh3LhA8atY738AGwMWpxFKQ1VNeci_r7SY"
|
||||
testKeyEC512PubY = "AXbmSeogEiDlDwz0Gc670YYByFzC3c7tEMeap7CckkOtuN0Yaebqtv42dZH0MiikzSco2ROhagX-HOinG7gB78ax"
|
||||
|
||||
// echo -n '{"crv":"P-256","kty":"EC","x":"<testKeyECPubX>","y":"<testKeyECPubY>"}' | \
|
||||
// openssl dgst -binary -sha256 | base64 | tr -d '=' | tr '/+' '_-'
|
||||
testKeyECThumbprint = "zedj-Bd1Zshp8KLePv2MB-lJ_Hagp7wAwdkA0NUTniU"
|
||||
)
|
||||
|
||||
var (
|
||||
testKey *rsa.PrivateKey
|
||||
testKeyEC *ecdsa.PrivateKey
|
||||
testKey *rsa.PrivateKey
|
||||
testKeyEC *ecdsa.PrivateKey
|
||||
testKeyEC384 *ecdsa.PrivateKey
|
||||
testKeyEC512 *ecdsa.PrivateKey
|
||||
)
|
||||
|
||||
func init() {
|
||||
d, _ := pem.Decode([]byte(testKeyPEM))
|
||||
if d == nil {
|
||||
panic("no block found in testKeyPEM")
|
||||
}
|
||||
var err error
|
||||
testKey, err = x509.ParsePKCS1PrivateKey(d.Bytes)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
testKey = parseRSA(testKeyPEM, "testKeyPEM")
|
||||
testKeyEC = parseEC(testKeyECPEM, "testKeyECPEM")
|
||||
testKeyEC384 = parseEC(testKeyEC384PEM, "testKeyEC384PEM")
|
||||
testKeyEC512 = parseEC(testKeyEC512PEM, "testKeyEC512PEM")
|
||||
}
|
||||
|
||||
if d, _ = pem.Decode([]byte(testKeyECPEM)); d == nil {
|
||||
panic("no block found in testKeyECPEM")
|
||||
func decodePEM(s, name string) []byte {
|
||||
d, _ := pem.Decode([]byte(s))
|
||||
if d == nil {
|
||||
panic("no block found in " + name)
|
||||
}
|
||||
testKeyEC, err = x509.ParseECPrivateKey(d.Bytes)
|
||||
return d.Bytes
|
||||
}
|
||||
|
||||
func parseRSA(s, name string) *rsa.PrivateKey {
|
||||
b := decodePEM(s, name)
|
||||
k, err := x509.ParsePKCS1PrivateKey(b)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
panic(fmt.Sprintf("%s: %v", name, err))
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func parseEC(s, name string) *ecdsa.PrivateKey {
|
||||
b := decodePEM(s, name)
|
||||
k, err := x509.ParseECPrivateKey(b)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("%s: %v", name, err))
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func TestJWSEncodeJSON(t *testing.T) {
|
||||
|
@ -141,50 +181,63 @@ func TestJWSEncodeJSON(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestJWSEncodeJSONEC(t *testing.T) {
|
||||
claims := struct{ Msg string }{"Hello JWS"}
|
||||
tt := []struct {
|
||||
key *ecdsa.PrivateKey
|
||||
x, y string
|
||||
alg, crv string
|
||||
}{
|
||||
{testKeyEC, testKeyECPubX, testKeyECPubY, "ES256", "P-256"},
|
||||
{testKeyEC384, testKeyEC384PubX, testKeyEC384PubY, "ES384", "P-384"},
|
||||
{testKeyEC512, testKeyEC512PubX, testKeyEC512PubY, "ES512", "P-521"},
|
||||
}
|
||||
for i, test := range tt {
|
||||
claims := struct{ Msg string }{"Hello JWS"}
|
||||
b, err := jwsEncodeJSON(claims, test.key, "nonce")
|
||||
if err != nil {
|
||||
t.Errorf("%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
var jws struct{ Protected, Payload, Signature string }
|
||||
if err := json.Unmarshal(b, &jws); err != nil {
|
||||
t.Errorf("%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
b, err := jwsEncodeJSON(claims, testKeyEC, "nonce")
|
||||
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 b, err = base64.RawURLEncoding.DecodeString(jws.Protected); err != nil {
|
||||
t.Fatalf("jws.Protected: %v", err)
|
||||
}
|
||||
var head struct {
|
||||
Alg string
|
||||
Nonce string
|
||||
JWK struct {
|
||||
Crv string
|
||||
Kty string
|
||||
X string
|
||||
Y string
|
||||
} `json:"jwk"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &head); err != nil {
|
||||
t.Fatalf("jws.Protected: %v", err)
|
||||
}
|
||||
if head.Alg != "ES256" {
|
||||
t.Errorf("head.Alg = %q; want ES256", head.Alg)
|
||||
}
|
||||
if head.Nonce != "nonce" {
|
||||
t.Errorf("head.Nonce = %q; want nonce", head.Nonce)
|
||||
}
|
||||
if head.JWK.Crv != "P-256" {
|
||||
t.Errorf("head.JWK.Crv = %q; want P-256", head.JWK.Crv)
|
||||
}
|
||||
if head.JWK.Kty != "EC" {
|
||||
t.Errorf("head.JWK.Kty = %q; want EC", head.JWK.Kty)
|
||||
}
|
||||
if head.JWK.X != testKeyECPubX {
|
||||
t.Errorf("head.JWK.X = %q; want %q", head.JWK.X, testKeyECPubX)
|
||||
}
|
||||
if head.JWK.Y != testKeyECPubY {
|
||||
t.Errorf("head.JWK.Y = %q; want %q", head.JWK.Y, testKeyECPubY)
|
||||
b, err = base64.RawURLEncoding.DecodeString(jws.Protected)
|
||||
if err != nil {
|
||||
t.Errorf("%d: jws.Protected: %v", i, err)
|
||||
}
|
||||
var head struct {
|
||||
Alg string
|
||||
Nonce string
|
||||
JWK struct {
|
||||
Crv string
|
||||
Kty string
|
||||
X string
|
||||
Y string
|
||||
} `json:"jwk"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &head); err != nil {
|
||||
t.Errorf("%d: jws.Protected: %v", i, err)
|
||||
}
|
||||
if head.Alg != test.alg {
|
||||
t.Errorf("%d: head.Alg = %q; want %q", i, head.Alg, test.alg)
|
||||
}
|
||||
if head.Nonce != "nonce" {
|
||||
t.Errorf("%d: head.Nonce = %q; want nonce", i, head.Nonce)
|
||||
}
|
||||
if head.JWK.Crv != test.crv {
|
||||
t.Errorf("%d: head.JWK.Crv = %q; want %q", i, head.JWK.Crv, test.crv)
|
||||
}
|
||||
if head.JWK.Kty != "EC" {
|
||||
t.Errorf("%d: head.JWK.Kty = %q; want EC", i, head.JWK.Kty)
|
||||
}
|
||||
if head.JWK.X != test.x {
|
||||
t.Errorf("%d: head.JWK.X = %q; want %q", i, head.JWK.X, test.x)
|
||||
}
|
||||
if head.JWK.Y != test.y {
|
||||
t.Errorf("%d: head.JWK.Y = %q; want %q", i, head.JWK.Y, test.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
// 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 acme
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ACME server response statuses used to describe Authorization and Challenge states.
|
||||
|
@ -33,14 +41,8 @@ const (
|
|||
CRLReasonAACompromise CRLReasonCode = 10
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrAuthorizationFailed indicates that an authorization for an identifier
|
||||
// did not succeed.
|
||||
ErrAuthorizationFailed = errors.New("acme: identifier authorization failed")
|
||||
|
||||
// ErrUnsupportedKey is returned when an unsupported key type is encountered.
|
||||
ErrUnsupportedKey = errors.New("acme: unknown key type; only RSA and ECDSA are supported")
|
||||
)
|
||||
// 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.
|
||||
|
@ -53,6 +55,7 @@ type Error struct {
|
|||
// Detail is a human-readable explanation specific to this occurrence of the problem.
|
||||
Detail string
|
||||
// Header is the original server error response headers.
|
||||
// It may be nil.
|
||||
Header http.Header
|
||||
}
|
||||
|
||||
|
@ -60,6 +63,50 @@ func (e *Error) Error() string {
|
|||
return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
|
||||
}
|
||||
|
||||
// AuthorizationError indicates that an authorization for an identifier
|
||||
// did not succeed.
|
||||
// It contains all errors from Challenge items of the failed Authorization.
|
||||
type AuthorizationError struct {
|
||||
// URI uniquely identifies the failed Authorization.
|
||||
URI string
|
||||
|
||||
// Identifier is an AuthzID.Value of the failed Authorization.
|
||||
Identifier string
|
||||
|
||||
// Errors is a collection of non-nil error values of Challenge items
|
||||
// of the failed Authorization.
|
||||
Errors []error
|
||||
}
|
||||
|
||||
func (a *AuthorizationError) Error() string {
|
||||
e := make([]string, len(a.Errors))
|
||||
for i, err := range a.Errors {
|
||||
e[i] = err.Error()
|
||||
}
|
||||
return fmt.Sprintf("acme: authorization error for %s: %s", a.Identifier, strings.Join(e, "; "))
|
||||
}
|
||||
|
||||
// RateLimit reports whether err represents a rate limit error and
|
||||
// any Retry-After duration returned by the server.
|
||||
//
|
||||
// See the following for more details on rate limiting:
|
||||
// https://tools.ietf.org/html/draft-ietf-acme-acme-05#section-5.6
|
||||
func RateLimit(err error) (time.Duration, bool) {
|
||||
e, ok := err.(*Error)
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
// Some CA implementations may return incorrect values.
|
||||
// Use case-insensitive comparison.
|
||||
if !strings.HasSuffix(strings.ToLower(e.ProblemType), ":ratelimited") {
|
||||
return 0, false
|
||||
}
|
||||
if e.Header == nil {
|
||||
return 0, true
|
||||
}
|
||||
return retryAfter(e.Header.Get("Retry-After"), 0), true
|
||||
}
|
||||
|
||||
// Account is a user account. It is associated with a private key.
|
||||
type Account struct {
|
||||
// URI is the account unique ID, which is also a URL used to retrieve
|
||||
|
@ -118,6 +165,8 @@ type Directory struct {
|
|||
}
|
||||
|
||||
// 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
|
||||
|
@ -130,6 +179,11 @@ type Challenge struct {
|
|||
|
||||
// Status identifies the status of this challenge.
|
||||
Status string
|
||||
|
||||
// Error indicates the reason for an authorization failure
|
||||
// when this challenge was used.
|
||||
// The type of a non-nil value is *Error.
|
||||
Error error
|
||||
}
|
||||
|
||||
// Authorization encodes an authorization response.
|
||||
|
@ -187,12 +241,26 @@ func (z *wireAuthz) authorization(uri string) *Authorization {
|
|||
return a
|
||||
}
|
||||
|
||||
func (z *wireAuthz) error(uri string) *AuthorizationError {
|
||||
err := &AuthorizationError{
|
||||
URI: uri,
|
||||
Identifier: z.Identifier.Value,
|
||||
}
|
||||
for _, raw := range z.Challenges {
|
||||
if raw.Error != nil {
|
||||
err.Errors = append(err.Errors, raw.Error.error(nil))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// wireChallenge is ACME JSON challenge representation.
|
||||
type wireChallenge struct {
|
||||
URI string `json:"uri"`
|
||||
Type string
|
||||
Token string
|
||||
Status string
|
||||
Error *wireError
|
||||
}
|
||||
|
||||
func (c *wireChallenge) challenge() *Challenge {
|
||||
|
@ -205,5 +273,57 @@ func (c *wireChallenge) challenge() *Challenge {
|
|||
if v.Status == "" {
|
||||
v.Status = StatusPending
|
||||
}
|
||||
if c.Error != nil {
|
||||
v.Error = c.Error.error(nil)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (e *wireError) error(h http.Header) *Error {
|
||||
return &Error{
|
||||
StatusCode: e.Status,
|
||||
ProblemType: e.Type,
|
||||
Detail: e.Detail,
|
||||
Header: h,
|
||||
}
|
||||
}
|
||||
|
||||
// CertOption is an optional argument type for the TLSSNIxChallengeCert methods for
|
||||
// customizing a temporary certificate for TLS-SNI challenges.
|
||||
type CertOption interface {
|
||||
privateCertOpt()
|
||||
}
|
||||
|
||||
// WithKey creates an option holding a private/public key pair.
|
||||
// The private part signs a certificate, and the public part represents the signee.
|
||||
func WithKey(key crypto.Signer) CertOption {
|
||||
return &certOptKey{key}
|
||||
}
|
||||
|
||||
type certOptKey struct {
|
||||
key crypto.Signer
|
||||
}
|
||||
|
||||
func (*certOptKey) privateCertOpt() {}
|
||||
|
||||
// WithTemplate creates an option for specifying a certificate template.
|
||||
// See x509.CreateCertificate for template usage details.
|
||||
//
|
||||
// In TLSSNIxChallengeCert methods, the template is also used as parent,
|
||||
// resulting in a self-signed certificate.
|
||||
// The DNSNames field of t is always overwritten for tls-sni challenge certs.
|
||||
func WithTemplate(t *x509.Certificate) CertOption {
|
||||
return (*certOptTemplate)(t)
|
||||
}
|
||||
|
||||
type certOptTemplate x509.Certificate
|
||||
|
||||
func (*certOptTemplate) privateCertOpt() {}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package acme
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRateLimit(t *testing.T) {
|
||||
now := time.Date(2017, 04, 27, 10, 0, 0, 0, time.UTC)
|
||||
f := timeNow
|
||||
defer func() { timeNow = f }()
|
||||
timeNow = func() time.Time { return now }
|
||||
|
||||
h120, hTime := http.Header{}, http.Header{}
|
||||
h120.Set("Retry-After", "120")
|
||||
hTime.Set("Retry-After", "Tue Apr 27 11:00:00 2017")
|
||||
|
||||
err1 := &Error{
|
||||
ProblemType: "urn:ietf:params:acme:error:nolimit",
|
||||
Header: h120,
|
||||
}
|
||||
err2 := &Error{
|
||||
ProblemType: "urn:ietf:params:acme:error:rateLimited",
|
||||
Header: h120,
|
||||
}
|
||||
err3 := &Error{
|
||||
ProblemType: "urn:ietf:params:acme:error:rateLimited",
|
||||
Header: nil,
|
||||
}
|
||||
err4 := &Error{
|
||||
ProblemType: "urn:ietf:params:acme:error:rateLimited",
|
||||
Header: hTime,
|
||||
}
|
||||
|
||||
tt := []struct {
|
||||
err error
|
||||
res time.Duration
|
||||
ok bool
|
||||
}{
|
||||
{nil, 0, false},
|
||||
{errors.New("dummy"), 0, false},
|
||||
{err1, 0, false},
|
||||
{err2, 2 * time.Minute, true},
|
||||
{err3, 0, true},
|
||||
{err4, time.Hour, true},
|
||||
}
|
||||
for i, test := range tt {
|
||||
res, ok := RateLimit(test.err)
|
||||
if ok != test.ok {
|
||||
t.Errorf("%d: RateLimit(%+v): ok = %v; want %v", i, test.err, ok, test.ok)
|
||||
continue
|
||||
}
|
||||
if res != test.res {
|
||||
t.Errorf("%d: RateLimit(%+v) = %v; want %v", i, test.err, res, test.res)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,9 +12,10 @@ import (
|
|||
"crypto/subtle"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/blowfish"
|
||||
"io"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/crypto/blowfish"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -205,7 +206,6 @@ func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
|
||||
|
||||
csalt, err := base64Decode(salt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -213,7 +213,8 @@ func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cip
|
|||
|
||||
// Bug compatibility with C bcrypt implementations. They use the trailing
|
||||
// NULL in the key string during expansion.
|
||||
ckey := append(key, 0)
|
||||
// We copy the key to prevent changing the underlying array.
|
||||
ckey := append(key[:len(key):len(key)], 0)
|
||||
|
||||
c, err := blowfish.NewSaltedCipher(ckey, csalt)
|
||||
if err != nil {
|
||||
|
|
|
@ -224,3 +224,20 @@ func BenchmarkGeneration(b *testing.B) {
|
|||
GenerateFromPassword(passwd, 10)
|
||||
}
|
||||
}
|
||||
|
||||
// See Issue https://github.com/golang/go/issues/20425.
|
||||
func TestNoSideEffectsFromCompare(t *testing.T) {
|
||||
source := []byte("passw0rd123456")
|
||||
password := source[:len(source)-6]
|
||||
token := source[len(source)-6:]
|
||||
want := make([]byte, len(source))
|
||||
copy(want, source)
|
||||
|
||||
wantHash := []byte("$2a$10$LK9XRuhNxHHCvjX3tdkRKei1QiCDUKrJRhZv7WWZPuQGRUM92rOUa")
|
||||
_ = CompareHashAndPassword(wantHash, password)
|
||||
|
||||
got := bytes.Join([][]byte{password, token}, []byte(""))
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Errorf("got=%q want=%q", got, want)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
// 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 blake2b implements the BLAKE2b hash algorithm defined by RFC 7693
|
||||
// and the extendable output function (XOF) BLAKE2Xb.
|
||||
//
|
||||
// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf
|
||||
// and for BLAKE2Xb see https://blake2.net/blake2x.pdf
|
||||
//
|
||||
// If you aren't sure which function you need, use BLAKE2b (Sum512 or New512).
|
||||
// If you need a secret-key MAC (message authentication code), use the New512
|
||||
// function with a non-nil key.
|
||||
//
|
||||
// BLAKE2X is a construction to compute hash values larger than 64 bytes. It
|
||||
// can produce hash values between 0 and 4 GiB.
|
||||
package blake2b
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash"
|
||||
)
|
||||
|
||||
const (
|
||||
// The blocksize of BLAKE2b in bytes.
|
||||
BlockSize = 128
|
||||
// The hash size of BLAKE2b-512 in bytes.
|
||||
Size = 64
|
||||
// The hash size of BLAKE2b-384 in bytes.
|
||||
Size384 = 48
|
||||
// The hash size of BLAKE2b-256 in bytes.
|
||||
Size256 = 32
|
||||
)
|
||||
|
||||
var (
|
||||
useAVX2 bool
|
||||
useAVX bool
|
||||
useSSE4 bool
|
||||
)
|
||||
|
||||
var errKeySize = errors.New("blake2b: invalid key size")
|
||||
|
||||
var iv = [8]uint64{
|
||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
|
||||
}
|
||||
|
||||
// Sum512 returns the BLAKE2b-512 checksum of the data.
|
||||
func Sum512(data []byte) [Size]byte {
|
||||
var sum [Size]byte
|
||||
checkSum(&sum, Size, data)
|
||||
return sum
|
||||
}
|
||||
|
||||
// Sum384 returns the BLAKE2b-384 checksum of the data.
|
||||
func Sum384(data []byte) [Size384]byte {
|
||||
var sum [Size]byte
|
||||
var sum384 [Size384]byte
|
||||
checkSum(&sum, Size384, data)
|
||||
copy(sum384[:], sum[:Size384])
|
||||
return sum384
|
||||
}
|
||||
|
||||
// Sum256 returns the BLAKE2b-256 checksum of the data.
|
||||
func Sum256(data []byte) [Size256]byte {
|
||||
var sum [Size]byte
|
||||
var sum256 [Size256]byte
|
||||
checkSum(&sum, Size256, data)
|
||||
copy(sum256[:], sum[:Size256])
|
||||
return sum256
|
||||
}
|
||||
|
||||
// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
|
||||
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
|
||||
func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
|
||||
|
||||
// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
|
||||
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
|
||||
func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
|
||||
|
||||
// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
|
||||
// key turns the hash into a MAC. The key must between zero and 64 bytes long.
|
||||
func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
|
||||
|
||||
func newDigest(hashSize int, key []byte) (*digest, error) {
|
||||
if len(key) > Size {
|
||||
return nil, errKeySize
|
||||
}
|
||||
d := &digest{
|
||||
size: hashSize,
|
||||
keyLen: len(key),
|
||||
}
|
||||
copy(d.key[:], key)
|
||||
d.Reset()
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func checkSum(sum *[Size]byte, hashSize int, data []byte) {
|
||||
h := iv
|
||||
h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24)
|
||||
var c [2]uint64
|
||||
|
||||
if length := len(data); length > BlockSize {
|
||||
n := length &^ (BlockSize - 1)
|
||||
if length == n {
|
||||
n -= BlockSize
|
||||
}
|
||||
hashBlocks(&h, &c, 0, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
|
||||
var block [BlockSize]byte
|
||||
offset := copy(block[:], data)
|
||||
remaining := uint64(BlockSize - offset)
|
||||
if c[0] < remaining {
|
||||
c[1]--
|
||||
}
|
||||
c[0] -= remaining
|
||||
|
||||
hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
|
||||
|
||||
for i, v := range h[:(hashSize+7)/8] {
|
||||
binary.LittleEndian.PutUint64(sum[8*i:], v)
|
||||
}
|
||||
}
|
||||
|
||||
type digest struct {
|
||||
h [8]uint64
|
||||
c [2]uint64
|
||||
size int
|
||||
block [BlockSize]byte
|
||||
offset int
|
||||
|
||||
key [BlockSize]byte
|
||||
keyLen int
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Size() int { return d.size }
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.h = iv
|
||||
d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24)
|
||||
d.offset, d.c[0], d.c[1] = 0, 0, 0
|
||||
if d.keyLen > 0 {
|
||||
d.block = d.key
|
||||
d.offset = BlockSize
|
||||
}
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
|
||||
if d.offset > 0 {
|
||||
remaining := BlockSize - d.offset
|
||||
if n <= remaining {
|
||||
d.offset += copy(d.block[d.offset:], p)
|
||||
return
|
||||
}
|
||||
copy(d.block[d.offset:], p[:remaining])
|
||||
hashBlocks(&d.h, &d.c, 0, d.block[:])
|
||||
d.offset = 0
|
||||
p = p[remaining:]
|
||||
}
|
||||
|
||||
if length := len(p); length > BlockSize {
|
||||
nn := length &^ (BlockSize - 1)
|
||||
if length == nn {
|
||||
nn -= BlockSize
|
||||
}
|
||||
hashBlocks(&d.h, &d.c, 0, p[:nn])
|
||||
p = p[nn:]
|
||||
}
|
||||
|
||||
if len(p) > 0 {
|
||||
d.offset += copy(d.block[:], p)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest) Sum(sum []byte) []byte {
|
||||
var hash [Size]byte
|
||||
d.finalize(&hash)
|
||||
return append(sum, hash[:d.size]...)
|
||||
}
|
||||
|
||||
func (d *digest) finalize(hash *[Size]byte) {
|
||||
var block [BlockSize]byte
|
||||
copy(block[:], d.block[:d.offset])
|
||||
remaining := uint64(BlockSize - d.offset)
|
||||
|
||||
c := d.c
|
||||
if c[0] < remaining {
|
||||
c[1]--
|
||||
}
|
||||
c[0] -= remaining
|
||||
|
||||
h := d.h
|
||||
hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
|
||||
|
||||
for i, v := range h {
|
||||
binary.LittleEndian.PutUint64(hash[8*i:], v)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
// 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.
|
||||
|
||||
// +build go1.7,amd64,!gccgo,!appengine
|
||||
|
||||
package blake2b
|
||||
|
||||
func init() {
|
||||
useAVX2 = supportsAVX2()
|
||||
useAVX = supportsAVX()
|
||||
useSSE4 = supportsSSE4()
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
func supportsSSE4() bool
|
||||
|
||||
//go:noescape
|
||||
func supportsAVX() bool
|
||||
|
||||
//go:noescape
|
||||
func supportsAVX2() bool
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
|
||||
func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
|
||||
if useAVX2 {
|
||||
hashBlocksAVX2(h, c, flag, blocks)
|
||||
} else if useAVX {
|
||||
hashBlocksAVX(h, c, flag, blocks)
|
||||
} else if useSSE4 {
|
||||
hashBlocksSSE4(h, c, flag, blocks)
|
||||
} else {
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,762 @@
|
|||
// 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.
|
||||
|
||||
// +build go1.7,amd64,!gccgo,!appengine
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
|
||||
DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
|
||||
DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b
|
||||
DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1
|
||||
GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32
|
||||
|
||||
DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1
|
||||
DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
|
||||
DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b
|
||||
DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179
|
||||
GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32
|
||||
|
||||
DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403
|
||||
DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
|
||||
DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403
|
||||
DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b
|
||||
GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32
|
||||
|
||||
DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302
|
||||
DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
|
||||
DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302
|
||||
DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a
|
||||
GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32
|
||||
|
||||
DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
|
||||
DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
|
||||
GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b
|
||||
DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1
|
||||
GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1
|
||||
DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
|
||||
GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b
|
||||
DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179
|
||||
GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403
|
||||
DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
|
||||
GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302
|
||||
DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
|
||||
GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39
|
||||
#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93
|
||||
#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e
|
||||
#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93
|
||||
#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39
|
||||
|
||||
#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \
|
||||
VPADDQ m0, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFD $-79, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPSHUFB c40, Y1, Y1; \
|
||||
VPADDQ m1, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFB c48, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPADDQ Y1, Y1, t; \
|
||||
VPSRLQ $63, Y1, Y1; \
|
||||
VPXOR t, Y1, Y1; \
|
||||
VPERMQ_0x39_Y1_Y1; \
|
||||
VPERMQ_0x4E_Y2_Y2; \
|
||||
VPERMQ_0x93_Y3_Y3; \
|
||||
VPADDQ m2, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFD $-79, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPSHUFB c40, Y1, Y1; \
|
||||
VPADDQ m3, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFB c48, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPADDQ Y1, Y1, t; \
|
||||
VPSRLQ $63, Y1, Y1; \
|
||||
VPXOR t, Y1, Y1; \
|
||||
VPERMQ_0x39_Y3_Y3; \
|
||||
VPERMQ_0x4E_Y2_Y2; \
|
||||
VPERMQ_0x93_Y1_Y1
|
||||
|
||||
#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E
|
||||
#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26
|
||||
#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E
|
||||
#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36
|
||||
#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E
|
||||
|
||||
#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n
|
||||
#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n
|
||||
#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n
|
||||
#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n
|
||||
#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n
|
||||
|
||||
#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01
|
||||
|
||||
#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01
|
||||
|
||||
#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8
|
||||
#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01
|
||||
|
||||
// load msg: Y12 = (i0, i1, i2, i3)
|
||||
// i0, i1, i2, i3 must not be 0
|
||||
#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \
|
||||
VMOVQ_SI_X12(i0*8); \
|
||||
VMOVQ_SI_X11(i2*8); \
|
||||
VPINSRQ_1_SI_X12(i1*8); \
|
||||
VPINSRQ_1_SI_X11(i3*8); \
|
||||
VINSERTI128 $1, X11, Y12, Y12
|
||||
|
||||
// load msg: Y13 = (i0, i1, i2, i3)
|
||||
// i0, i1, i2, i3 must not be 0
|
||||
#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \
|
||||
VMOVQ_SI_X13(i0*8); \
|
||||
VMOVQ_SI_X11(i2*8); \
|
||||
VPINSRQ_1_SI_X13(i1*8); \
|
||||
VPINSRQ_1_SI_X11(i3*8); \
|
||||
VINSERTI128 $1, X11, Y13, Y13
|
||||
|
||||
// load msg: Y14 = (i0, i1, i2, i3)
|
||||
// i0, i1, i2, i3 must not be 0
|
||||
#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \
|
||||
VMOVQ_SI_X14(i0*8); \
|
||||
VMOVQ_SI_X11(i2*8); \
|
||||
VPINSRQ_1_SI_X14(i1*8); \
|
||||
VPINSRQ_1_SI_X11(i3*8); \
|
||||
VINSERTI128 $1, X11, Y14, Y14
|
||||
|
||||
// load msg: Y15 = (i0, i1, i2, i3)
|
||||
// i0, i1, i2, i3 must not be 0
|
||||
#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \
|
||||
VMOVQ_SI_X15(i0*8); \
|
||||
VMOVQ_SI_X11(i2*8); \
|
||||
VPINSRQ_1_SI_X15(i1*8); \
|
||||
VPINSRQ_1_SI_X11(i3*8); \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \
|
||||
VMOVQ_SI_X12_0; \
|
||||
VMOVQ_SI_X11(4*8); \
|
||||
VPINSRQ_1_SI_X12(2*8); \
|
||||
VPINSRQ_1_SI_X11(6*8); \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
LOAD_MSG_AVX2_Y13(1, 3, 5, 7); \
|
||||
LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \
|
||||
LOAD_MSG_AVX2_Y15(9, 11, 13, 15)
|
||||
|
||||
#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \
|
||||
LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \
|
||||
LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \
|
||||
VMOVQ_SI_X11(11*8); \
|
||||
VPSHUFD $0x4E, 0*8(SI), X14; \
|
||||
VPINSRQ_1_SI_X11(5*8); \
|
||||
VINSERTI128 $1, X11, Y14, Y14; \
|
||||
LOAD_MSG_AVX2_Y15(12, 2, 7, 3)
|
||||
|
||||
#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \
|
||||
VMOVQ_SI_X11(5*8); \
|
||||
VMOVDQU 11*8(SI), X12; \
|
||||
VPINSRQ_1_SI_X11(15*8); \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
VMOVQ_SI_X13(8*8); \
|
||||
VMOVQ_SI_X11(2*8); \
|
||||
VPINSRQ_1_SI_X13_0; \
|
||||
VPINSRQ_1_SI_X11(13*8); \
|
||||
VINSERTI128 $1, X11, Y13, Y13; \
|
||||
LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \
|
||||
LOAD_MSG_AVX2_Y15(14, 6, 1, 4)
|
||||
|
||||
#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \
|
||||
LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \
|
||||
LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \
|
||||
LOAD_MSG_AVX2_Y14(2, 5, 4, 15); \
|
||||
VMOVQ_SI_X15(6*8); \
|
||||
VMOVQ_SI_X11_0; \
|
||||
VPINSRQ_1_SI_X15(10*8); \
|
||||
VPINSRQ_1_SI_X11(8*8); \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \
|
||||
LOAD_MSG_AVX2_Y12(9, 5, 2, 10); \
|
||||
VMOVQ_SI_X13_0; \
|
||||
VMOVQ_SI_X11(4*8); \
|
||||
VPINSRQ_1_SI_X13(7*8); \
|
||||
VPINSRQ_1_SI_X11(15*8); \
|
||||
VINSERTI128 $1, X11, Y13, Y13; \
|
||||
LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \
|
||||
LOAD_MSG_AVX2_Y15(1, 12, 8, 13)
|
||||
|
||||
#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \
|
||||
VMOVQ_SI_X12(2*8); \
|
||||
VMOVQ_SI_X11_0; \
|
||||
VPINSRQ_1_SI_X12(6*8); \
|
||||
VPINSRQ_1_SI_X11(8*8); \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \
|
||||
LOAD_MSG_AVX2_Y14(4, 7, 15, 1); \
|
||||
LOAD_MSG_AVX2_Y15(13, 5, 14, 9)
|
||||
|
||||
#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \
|
||||
LOAD_MSG_AVX2_Y12(12, 1, 14, 4); \
|
||||
LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \
|
||||
VMOVQ_SI_X14_0; \
|
||||
VPSHUFD $0x4E, 8*8(SI), X11; \
|
||||
VPINSRQ_1_SI_X14(6*8); \
|
||||
VINSERTI128 $1, X11, Y14, Y14; \
|
||||
LOAD_MSG_AVX2_Y15(7, 3, 2, 11)
|
||||
|
||||
#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \
|
||||
LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \
|
||||
LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \
|
||||
LOAD_MSG_AVX2_Y14(5, 15, 8, 2); \
|
||||
VMOVQ_SI_X15_0; \
|
||||
VMOVQ_SI_X11(6*8); \
|
||||
VPINSRQ_1_SI_X15(4*8); \
|
||||
VPINSRQ_1_SI_X11(10*8); \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \
|
||||
VMOVQ_SI_X12(6*8); \
|
||||
VMOVQ_SI_X11(11*8); \
|
||||
VPINSRQ_1_SI_X12(14*8); \
|
||||
VPINSRQ_1_SI_X11_0; \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \
|
||||
VMOVQ_SI_X11(1*8); \
|
||||
VMOVDQU 12*8(SI), X14; \
|
||||
VPINSRQ_1_SI_X11(10*8); \
|
||||
VINSERTI128 $1, X11, Y14, Y14; \
|
||||
VMOVQ_SI_X15(2*8); \
|
||||
VMOVDQU 4*8(SI), X11; \
|
||||
VPINSRQ_1_SI_X15(7*8); \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \
|
||||
LOAD_MSG_AVX2_Y12(10, 8, 7, 1); \
|
||||
VMOVQ_SI_X13(2*8); \
|
||||
VPSHUFD $0x4E, 5*8(SI), X11; \
|
||||
VPINSRQ_1_SI_X13(4*8); \
|
||||
VINSERTI128 $1, X11, Y13, Y13; \
|
||||
LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \
|
||||
VMOVQ_SI_X15(11*8); \
|
||||
VMOVQ_SI_X11(12*8); \
|
||||
VPINSRQ_1_SI_X15(14*8); \
|
||||
VPINSRQ_1_SI_X11_0; \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
// func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
TEXT ·hashBlocksAVX2(SB), 4, $320-48 // frame size = 288 + 32 byte alignment
|
||||
MOVQ h+0(FP), AX
|
||||
MOVQ c+8(FP), BX
|
||||
MOVQ flag+16(FP), CX
|
||||
MOVQ blocks_base+24(FP), SI
|
||||
MOVQ blocks_len+32(FP), DI
|
||||
|
||||
MOVQ SP, DX
|
||||
MOVQ SP, R9
|
||||
ADDQ $31, R9
|
||||
ANDQ $~31, R9
|
||||
MOVQ R9, SP
|
||||
|
||||
MOVQ CX, 16(SP)
|
||||
XORQ CX, CX
|
||||
MOVQ CX, 24(SP)
|
||||
|
||||
VMOVDQU ·AVX2_c40<>(SB), Y4
|
||||
VMOVDQU ·AVX2_c48<>(SB), Y5
|
||||
|
||||
VMOVDQU 0(AX), Y8
|
||||
VMOVDQU 32(AX), Y9
|
||||
VMOVDQU ·AVX2_iv0<>(SB), Y6
|
||||
VMOVDQU ·AVX2_iv1<>(SB), Y7
|
||||
|
||||
MOVQ 0(BX), R8
|
||||
MOVQ 8(BX), R9
|
||||
MOVQ R9, 8(SP)
|
||||
|
||||
loop:
|
||||
ADDQ $128, R8
|
||||
MOVQ R8, 0(SP)
|
||||
CMPQ R8, $128
|
||||
JGE noinc
|
||||
INCQ R9
|
||||
MOVQ R9, 8(SP)
|
||||
|
||||
noinc:
|
||||
VMOVDQA Y8, Y0
|
||||
VMOVDQA Y9, Y1
|
||||
VMOVDQA Y6, Y2
|
||||
VPXOR 0(SP), Y7, Y3
|
||||
|
||||
LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15()
|
||||
VMOVDQA Y12, 32(SP)
|
||||
VMOVDQA Y13, 64(SP)
|
||||
VMOVDQA Y14, 96(SP)
|
||||
VMOVDQA Y15, 128(SP)
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3()
|
||||
VMOVDQA Y12, 160(SP)
|
||||
VMOVDQA Y13, 192(SP)
|
||||
VMOVDQA Y14, 224(SP)
|
||||
VMOVDQA Y15, 256(SP)
|
||||
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
|
||||
ROUND_AVX2(32(SP), 64(SP), 96(SP), 128(SP), Y10, Y4, Y5)
|
||||
ROUND_AVX2(160(SP), 192(SP), 224(SP), 256(SP), Y10, Y4, Y5)
|
||||
|
||||
VPXOR Y0, Y8, Y8
|
||||
VPXOR Y1, Y9, Y9
|
||||
VPXOR Y2, Y8, Y8
|
||||
VPXOR Y3, Y9, Y9
|
||||
|
||||
LEAQ 128(SI), SI
|
||||
SUBQ $128, DI
|
||||
JNE loop
|
||||
|
||||
MOVQ R8, 0(BX)
|
||||
MOVQ R9, 8(BX)
|
||||
|
||||
VMOVDQU Y8, 0(AX)
|
||||
VMOVDQU Y9, 32(AX)
|
||||
VZEROUPPER
|
||||
|
||||
MOVQ DX, SP
|
||||
RET
|
||||
|
||||
#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA
|
||||
#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB
|
||||
#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF
|
||||
#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD
|
||||
#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE
|
||||
|
||||
#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7
|
||||
#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF
|
||||
#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7
|
||||
#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF
|
||||
#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7
|
||||
#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7
|
||||
#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF
|
||||
#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF
|
||||
|
||||
#define SHUFFLE_AVX() \
|
||||
VMOVDQA X6, X13; \
|
||||
VMOVDQA X2, X14; \
|
||||
VMOVDQA X4, X6; \
|
||||
VPUNPCKLQDQ_X13_X13_X15; \
|
||||
VMOVDQA X5, X4; \
|
||||
VMOVDQA X6, X5; \
|
||||
VPUNPCKHQDQ_X15_X7_X6; \
|
||||
VPUNPCKLQDQ_X7_X7_X15; \
|
||||
VPUNPCKHQDQ_X15_X13_X7; \
|
||||
VPUNPCKLQDQ_X3_X3_X15; \
|
||||
VPUNPCKHQDQ_X15_X2_X2; \
|
||||
VPUNPCKLQDQ_X14_X14_X15; \
|
||||
VPUNPCKHQDQ_X15_X3_X3; \
|
||||
|
||||
#define SHUFFLE_AVX_INV() \
|
||||
VMOVDQA X2, X13; \
|
||||
VMOVDQA X4, X14; \
|
||||
VPUNPCKLQDQ_X2_X2_X15; \
|
||||
VMOVDQA X5, X4; \
|
||||
VPUNPCKHQDQ_X15_X3_X2; \
|
||||
VMOVDQA X14, X5; \
|
||||
VPUNPCKLQDQ_X3_X3_X15; \
|
||||
VMOVDQA X6, X14; \
|
||||
VPUNPCKHQDQ_X15_X13_X3; \
|
||||
VPUNPCKLQDQ_X7_X7_X15; \
|
||||
VPUNPCKHQDQ_X15_X6_X6; \
|
||||
VPUNPCKLQDQ_X14_X14_X15; \
|
||||
VPUNPCKHQDQ_X15_X7_X7; \
|
||||
|
||||
#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
|
||||
VPADDQ m0, v0, v0; \
|
||||
VPADDQ v2, v0, v0; \
|
||||
VPADDQ m1, v1, v1; \
|
||||
VPADDQ v3, v1, v1; \
|
||||
VPXOR v0, v6, v6; \
|
||||
VPXOR v1, v7, v7; \
|
||||
VPSHUFD $-79, v6, v6; \
|
||||
VPSHUFD $-79, v7, v7; \
|
||||
VPADDQ v6, v4, v4; \
|
||||
VPADDQ v7, v5, v5; \
|
||||
VPXOR v4, v2, v2; \
|
||||
VPXOR v5, v3, v3; \
|
||||
VPSHUFB c40, v2, v2; \
|
||||
VPSHUFB c40, v3, v3; \
|
||||
VPADDQ m2, v0, v0; \
|
||||
VPADDQ v2, v0, v0; \
|
||||
VPADDQ m3, v1, v1; \
|
||||
VPADDQ v3, v1, v1; \
|
||||
VPXOR v0, v6, v6; \
|
||||
VPXOR v1, v7, v7; \
|
||||
VPSHUFB c48, v6, v6; \
|
||||
VPSHUFB c48, v7, v7; \
|
||||
VPADDQ v6, v4, v4; \
|
||||
VPADDQ v7, v5, v5; \
|
||||
VPXOR v4, v2, v2; \
|
||||
VPXOR v5, v3, v3; \
|
||||
VPADDQ v2, v2, t0; \
|
||||
VPSRLQ $63, v2, v2; \
|
||||
VPXOR t0, v2, v2; \
|
||||
VPADDQ v3, v3, t0; \
|
||||
VPSRLQ $63, v3, v3; \
|
||||
VPXOR t0, v3, v3
|
||||
|
||||
// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7)
|
||||
// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0
|
||||
#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \
|
||||
VMOVQ_SI_X12(i0*8); \
|
||||
VMOVQ_SI_X13(i2*8); \
|
||||
VMOVQ_SI_X14(i4*8); \
|
||||
VMOVQ_SI_X15(i6*8); \
|
||||
VPINSRQ_1_SI_X12(i1*8); \
|
||||
VPINSRQ_1_SI_X13(i3*8); \
|
||||
VPINSRQ_1_SI_X14(i5*8); \
|
||||
VPINSRQ_1_SI_X15(i7*8)
|
||||
|
||||
// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7)
|
||||
#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \
|
||||
VMOVQ_SI_X12_0; \
|
||||
VMOVQ_SI_X13(4*8); \
|
||||
VMOVQ_SI_X14(1*8); \
|
||||
VMOVQ_SI_X15(5*8); \
|
||||
VPINSRQ_1_SI_X12(2*8); \
|
||||
VPINSRQ_1_SI_X13(6*8); \
|
||||
VPINSRQ_1_SI_X14(3*8); \
|
||||
VPINSRQ_1_SI_X15(7*8)
|
||||
|
||||
// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3)
|
||||
#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \
|
||||
VPSHUFD $0x4E, 0*8(SI), X12; \
|
||||
VMOVQ_SI_X13(11*8); \
|
||||
VMOVQ_SI_X14(12*8); \
|
||||
VMOVQ_SI_X15(7*8); \
|
||||
VPINSRQ_1_SI_X13(5*8); \
|
||||
VPINSRQ_1_SI_X14(2*8); \
|
||||
VPINSRQ_1_SI_X15(3*8)
|
||||
|
||||
// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13)
|
||||
#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \
|
||||
VMOVDQU 11*8(SI), X12; \
|
||||
VMOVQ_SI_X13(5*8); \
|
||||
VMOVQ_SI_X14(8*8); \
|
||||
VMOVQ_SI_X15(2*8); \
|
||||
VPINSRQ_1_SI_X13(15*8); \
|
||||
VPINSRQ_1_SI_X14_0; \
|
||||
VPINSRQ_1_SI_X15(13*8)
|
||||
|
||||
// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8)
|
||||
#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \
|
||||
VMOVQ_SI_X12(2*8); \
|
||||
VMOVQ_SI_X13(4*8); \
|
||||
VMOVQ_SI_X14(6*8); \
|
||||
VMOVQ_SI_X15_0; \
|
||||
VPINSRQ_1_SI_X12(5*8); \
|
||||
VPINSRQ_1_SI_X13(15*8); \
|
||||
VPINSRQ_1_SI_X14(10*8); \
|
||||
VPINSRQ_1_SI_X15(8*8)
|
||||
|
||||
// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15)
|
||||
#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \
|
||||
VMOVQ_SI_X12(9*8); \
|
||||
VMOVQ_SI_X13(2*8); \
|
||||
VMOVQ_SI_X14_0; \
|
||||
VMOVQ_SI_X15(4*8); \
|
||||
VPINSRQ_1_SI_X12(5*8); \
|
||||
VPINSRQ_1_SI_X13(10*8); \
|
||||
VPINSRQ_1_SI_X14(7*8); \
|
||||
VPINSRQ_1_SI_X15(15*8)
|
||||
|
||||
// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3)
|
||||
#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \
|
||||
VMOVQ_SI_X12(2*8); \
|
||||
VMOVQ_SI_X13_0; \
|
||||
VMOVQ_SI_X14(12*8); \
|
||||
VMOVQ_SI_X15(11*8); \
|
||||
VPINSRQ_1_SI_X12(6*8); \
|
||||
VPINSRQ_1_SI_X13(8*8); \
|
||||
VPINSRQ_1_SI_X14(10*8); \
|
||||
VPINSRQ_1_SI_X15(3*8)
|
||||
|
||||
// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11)
|
||||
#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \
|
||||
MOVQ 0*8(SI), X12; \
|
||||
VPSHUFD $0x4E, 8*8(SI), X13; \
|
||||
MOVQ 7*8(SI), X14; \
|
||||
MOVQ 2*8(SI), X15; \
|
||||
VPINSRQ_1_SI_X12(6*8); \
|
||||
VPINSRQ_1_SI_X14(3*8); \
|
||||
VPINSRQ_1_SI_X15(11*8)
|
||||
|
||||
// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8)
|
||||
#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \
|
||||
MOVQ 6*8(SI), X12; \
|
||||
MOVQ 11*8(SI), X13; \
|
||||
MOVQ 15*8(SI), X14; \
|
||||
MOVQ 3*8(SI), X15; \
|
||||
VPINSRQ_1_SI_X12(14*8); \
|
||||
VPINSRQ_1_SI_X13_0; \
|
||||
VPINSRQ_1_SI_X14(9*8); \
|
||||
VPINSRQ_1_SI_X15(8*8)
|
||||
|
||||
// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10)
|
||||
#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \
|
||||
MOVQ 5*8(SI), X12; \
|
||||
MOVQ 8*8(SI), X13; \
|
||||
MOVQ 0*8(SI), X14; \
|
||||
MOVQ 6*8(SI), X15; \
|
||||
VPINSRQ_1_SI_X12(15*8); \
|
||||
VPINSRQ_1_SI_X13(2*8); \
|
||||
VPINSRQ_1_SI_X14(4*8); \
|
||||
VPINSRQ_1_SI_X15(10*8)
|
||||
|
||||
// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5)
|
||||
#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \
|
||||
VMOVDQU 12*8(SI), X12; \
|
||||
MOVQ 1*8(SI), X13; \
|
||||
MOVQ 2*8(SI), X14; \
|
||||
VPINSRQ_1_SI_X13(10*8); \
|
||||
VPINSRQ_1_SI_X14(7*8); \
|
||||
VMOVDQU 4*8(SI), X15
|
||||
|
||||
// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0)
|
||||
#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \
|
||||
MOVQ 15*8(SI), X12; \
|
||||
MOVQ 3*8(SI), X13; \
|
||||
MOVQ 11*8(SI), X14; \
|
||||
MOVQ 12*8(SI), X15; \
|
||||
VPINSRQ_1_SI_X12(9*8); \
|
||||
VPINSRQ_1_SI_X13(13*8); \
|
||||
VPINSRQ_1_SI_X14(14*8); \
|
||||
VPINSRQ_1_SI_X15_0
|
||||
|
||||
// func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
|
||||
MOVQ h+0(FP), AX
|
||||
MOVQ c+8(FP), BX
|
||||
MOVQ flag+16(FP), CX
|
||||
MOVQ blocks_base+24(FP), SI
|
||||
MOVQ blocks_len+32(FP), DI
|
||||
|
||||
MOVQ SP, BP
|
||||
MOVQ SP, R9
|
||||
ADDQ $15, R9
|
||||
ANDQ $~15, R9
|
||||
MOVQ R9, SP
|
||||
|
||||
VMOVDQU ·AVX_c40<>(SB), X0
|
||||
VMOVDQU ·AVX_c48<>(SB), X1
|
||||
VMOVDQA X0, X8
|
||||
VMOVDQA X1, X9
|
||||
|
||||
VMOVDQU ·AVX_iv3<>(SB), X0
|
||||
VMOVDQA X0, 0(SP)
|
||||
XORQ CX, 0(SP) // 0(SP) = ·AVX_iv3 ^ (CX || 0)
|
||||
|
||||
VMOVDQU 0(AX), X10
|
||||
VMOVDQU 16(AX), X11
|
||||
VMOVDQU 32(AX), X2
|
||||
VMOVDQU 48(AX), X3
|
||||
|
||||
MOVQ 0(BX), R8
|
||||
MOVQ 8(BX), R9
|
||||
|
||||
loop:
|
||||
ADDQ $128, R8
|
||||
CMPQ R8, $128
|
||||
JGE noinc
|
||||
INCQ R9
|
||||
|
||||
noinc:
|
||||
VMOVQ_R8_X15
|
||||
VPINSRQ_1_R9_X15
|
||||
|
||||
VMOVDQA X10, X0
|
||||
VMOVDQA X11, X1
|
||||
VMOVDQU ·AVX_iv0<>(SB), X4
|
||||
VMOVDQU ·AVX_iv1<>(SB), X5
|
||||
VMOVDQU ·AVX_iv2<>(SB), X6
|
||||
|
||||
VPXOR X15, X6, X6
|
||||
VMOVDQA 0(SP), X7
|
||||
|
||||
LOAD_MSG_AVX_0_2_4_6_1_3_5_7()
|
||||
VMOVDQA X12, 16(SP)
|
||||
VMOVDQA X13, 32(SP)
|
||||
VMOVDQA X14, 48(SP)
|
||||
VMOVDQA X15, 64(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15)
|
||||
VMOVDQA X12, 80(SP)
|
||||
VMOVDQA X13, 96(SP)
|
||||
VMOVDQA X14, 112(SP)
|
||||
VMOVDQA X15, 128(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6)
|
||||
VMOVDQA X12, 144(SP)
|
||||
VMOVDQA X13, 160(SP)
|
||||
VMOVDQA X14, 176(SP)
|
||||
VMOVDQA X15, 192(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX_1_0_11_5_12_2_7_3()
|
||||
VMOVDQA X12, 208(SP)
|
||||
VMOVDQA X13, 224(SP)
|
||||
VMOVDQA X14, 240(SP)
|
||||
VMOVDQA X15, 256(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX_11_12_5_15_8_0_2_13()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX_2_5_4_15_6_10_0_8()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX_9_5_2_10_0_7_4_15()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX_2_6_0_8_12_10_11_3()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX_0_6_9_8_7_3_2_11()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX_5_15_8_2_0_4_6_10()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX_6_14_11_0_15_9_3_8()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX_12_13_1_10_2_7_4_5()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX_15_9_3_13_11_14_12_0()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
VMOVDQU 32(AX), X14
|
||||
VMOVDQU 48(AX), X15
|
||||
VPXOR X0, X10, X10
|
||||
VPXOR X1, X11, X11
|
||||
VPXOR X2, X14, X14
|
||||
VPXOR X3, X15, X15
|
||||
VPXOR X4, X10, X10
|
||||
VPXOR X5, X11, X11
|
||||
VPXOR X6, X14, X2
|
||||
VPXOR X7, X15, X3
|
||||
VMOVDQU X2, 32(AX)
|
||||
VMOVDQU X3, 48(AX)
|
||||
|
||||
LEAQ 128(SI), SI
|
||||
SUBQ $128, DI
|
||||
JNE loop
|
||||
|
||||
VMOVDQU X10, 0(AX)
|
||||
VMOVDQU X11, 16(AX)
|
||||
|
||||
MOVQ R8, 0(BX)
|
||||
MOVQ R9, 8(BX)
|
||||
VZEROUPPER
|
||||
|
||||
MOVQ BP, SP
|
||||
RET
|
||||
|
||||
// func supportsAVX2() bool
|
||||
TEXT ·supportsAVX2(SB), 4, $0-1
|
||||
MOVQ runtime·support_avx2(SB), AX
|
||||
MOVB AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func supportsAVX() bool
|
||||
TEXT ·supportsAVX(SB), 4, $0-1
|
||||
MOVQ runtime·support_avx(SB), AX
|
||||
MOVB AX, ret+0(FP)
|
||||
RET
|
|
@ -0,0 +1,25 @@
|
|||
// 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.
|
||||
|
||||
// +build !go1.7,amd64,!gccgo,!appengine
|
||||
|
||||
package blake2b
|
||||
|
||||
func init() {
|
||||
useSSE4 = supportsSSE4()
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
func supportsSSE4() bool
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
|
||||
func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
|
||||
if useSSE4 {
|
||||
hashBlocksSSE4(h, c, flag, blocks)
|
||||
} else {
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,290 @@
|
|||
// 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.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908
|
||||
DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b
|
||||
GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b
|
||||
DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1
|
||||
GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1
|
||||
DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f
|
||||
GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b
|
||||
DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179
|
||||
GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·c40<>+0x00(SB)/8, $0x0201000706050403
|
||||
DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b
|
||||
GLOBL ·c40<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA ·c48<>+0x00(SB)/8, $0x0100070605040302
|
||||
DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
|
||||
GLOBL ·c48<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \
|
||||
MOVO v4, t1; \
|
||||
MOVO v5, v4; \
|
||||
MOVO t1, v5; \
|
||||
MOVO v6, t1; \
|
||||
PUNPCKLQDQ v6, t2; \
|
||||
PUNPCKHQDQ v7, v6; \
|
||||
PUNPCKHQDQ t2, v6; \
|
||||
PUNPCKLQDQ v7, t2; \
|
||||
MOVO t1, v7; \
|
||||
MOVO v2, t1; \
|
||||
PUNPCKHQDQ t2, v7; \
|
||||
PUNPCKLQDQ v3, t2; \
|
||||
PUNPCKHQDQ t2, v2; \
|
||||
PUNPCKLQDQ t1, t2; \
|
||||
PUNPCKHQDQ t2, v3
|
||||
|
||||
#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \
|
||||
MOVO v4, t1; \
|
||||
MOVO v5, v4; \
|
||||
MOVO t1, v5; \
|
||||
MOVO v2, t1; \
|
||||
PUNPCKLQDQ v2, t2; \
|
||||
PUNPCKHQDQ v3, v2; \
|
||||
PUNPCKHQDQ t2, v2; \
|
||||
PUNPCKLQDQ v3, t2; \
|
||||
MOVO t1, v3; \
|
||||
MOVO v6, t1; \
|
||||
PUNPCKHQDQ t2, v3; \
|
||||
PUNPCKLQDQ v7, t2; \
|
||||
PUNPCKHQDQ t2, v6; \
|
||||
PUNPCKLQDQ t1, t2; \
|
||||
PUNPCKHQDQ t2, v7
|
||||
|
||||
#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
|
||||
PADDQ m0, v0; \
|
||||
PADDQ m1, v1; \
|
||||
PADDQ v2, v0; \
|
||||
PADDQ v3, v1; \
|
||||
PXOR v0, v6; \
|
||||
PXOR v1, v7; \
|
||||
PSHUFD $0xB1, v6, v6; \
|
||||
PSHUFD $0xB1, v7, v7; \
|
||||
PADDQ v6, v4; \
|
||||
PADDQ v7, v5; \
|
||||
PXOR v4, v2; \
|
||||
PXOR v5, v3; \
|
||||
PSHUFB c40, v2; \
|
||||
PSHUFB c40, v3; \
|
||||
PADDQ m2, v0; \
|
||||
PADDQ m3, v1; \
|
||||
PADDQ v2, v0; \
|
||||
PADDQ v3, v1; \
|
||||
PXOR v0, v6; \
|
||||
PXOR v1, v7; \
|
||||
PSHUFB c48, v6; \
|
||||
PSHUFB c48, v7; \
|
||||
PADDQ v6, v4; \
|
||||
PADDQ v7, v5; \
|
||||
PXOR v4, v2; \
|
||||
PXOR v5, v3; \
|
||||
MOVOU v2, t0; \
|
||||
PADDQ v2, t0; \
|
||||
PSRLQ $63, v2; \
|
||||
PXOR t0, v2; \
|
||||
MOVOU v3, t0; \
|
||||
PADDQ v3, t0; \
|
||||
PSRLQ $63, v3; \
|
||||
PXOR t0, v3
|
||||
|
||||
#define LOAD_MSG(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7) \
|
||||
MOVQ i0*8(src), m0; \
|
||||
PINSRQ $1, i1*8(src), m0; \
|
||||
MOVQ i2*8(src), m1; \
|
||||
PINSRQ $1, i3*8(src), m1; \
|
||||
MOVQ i4*8(src), m2; \
|
||||
PINSRQ $1, i5*8(src), m2; \
|
||||
MOVQ i6*8(src), m3; \
|
||||
PINSRQ $1, i7*8(src), m3
|
||||
|
||||
// func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
TEXT ·hashBlocksSSE4(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
|
||||
MOVQ h+0(FP), AX
|
||||
MOVQ c+8(FP), BX
|
||||
MOVQ flag+16(FP), CX
|
||||
MOVQ blocks_base+24(FP), SI
|
||||
MOVQ blocks_len+32(FP), DI
|
||||
|
||||
MOVQ SP, BP
|
||||
MOVQ SP, R9
|
||||
ADDQ $15, R9
|
||||
ANDQ $~15, R9
|
||||
MOVQ R9, SP
|
||||
|
||||
MOVOU ·iv3<>(SB), X0
|
||||
MOVO X0, 0(SP)
|
||||
XORQ CX, 0(SP) // 0(SP) = ·iv3 ^ (CX || 0)
|
||||
|
||||
MOVOU ·c40<>(SB), X13
|
||||
MOVOU ·c48<>(SB), X14
|
||||
|
||||
MOVOU 0(AX), X12
|
||||
MOVOU 16(AX), X15
|
||||
|
||||
MOVQ 0(BX), R8
|
||||
MOVQ 8(BX), R9
|
||||
|
||||
loop:
|
||||
ADDQ $128, R8
|
||||
CMPQ R8, $128
|
||||
JGE noinc
|
||||
INCQ R9
|
||||
|
||||
noinc:
|
||||
MOVQ R8, X8
|
||||
PINSRQ $1, R9, X8
|
||||
|
||||
MOVO X12, X0
|
||||
MOVO X15, X1
|
||||
MOVOU 32(AX), X2
|
||||
MOVOU 48(AX), X3
|
||||
MOVOU ·iv0<>(SB), X4
|
||||
MOVOU ·iv1<>(SB), X5
|
||||
MOVOU ·iv2<>(SB), X6
|
||||
|
||||
PXOR X8, X6
|
||||
MOVO 0(SP), X7
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7)
|
||||
MOVO X8, 16(SP)
|
||||
MOVO X9, 32(SP)
|
||||
MOVO X10, 48(SP)
|
||||
MOVO X11, 64(SP)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 8, 10, 12, 14, 9, 11, 13, 15)
|
||||
MOVO X8, 80(SP)
|
||||
MOVO X9, 96(SP)
|
||||
MOVO X10, 112(SP)
|
||||
MOVO X11, 128(SP)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6)
|
||||
MOVO X8, 144(SP)
|
||||
MOVO X9, 160(SP)
|
||||
MOVO X10, 176(SP)
|
||||
MOVO X11, 192(SP)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 1, 0, 11, 5, 12, 2, 7, 3)
|
||||
MOVO X8, 208(SP)
|
||||
MOVO X9, 224(SP)
|
||||
MOVO X10, 240(SP)
|
||||
MOVO X11, 256(SP)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 10, 3, 7, 9, 14, 6, 1, 4)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 2, 5, 4, 15, 6, 10, 0, 8)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 14, 11, 6, 3, 1, 12, 8, 13)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 4, 7, 15, 1, 13, 5, 14, 9)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 0, 6, 9, 8, 7, 3, 2, 11)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 5, 15, 8, 2, 0, 4, 6, 10)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 12, 13, 1, 10, 2, 7, 4, 5)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
LOAD_MSG(X8, X9, X10, X11, SI, 15, 9, 3, 13, 11, 14, 12, 0)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X11, X13, X14)
|
||||
SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X11, X13, X14)
|
||||
SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9)
|
||||
|
||||
MOVOU 32(AX), X10
|
||||
MOVOU 48(AX), X11
|
||||
PXOR X0, X12
|
||||
PXOR X1, X15
|
||||
PXOR X2, X10
|
||||
PXOR X3, X11
|
||||
PXOR X4, X12
|
||||
PXOR X5, X15
|
||||
PXOR X6, X10
|
||||
PXOR X7, X11
|
||||
MOVOU X10, 32(AX)
|
||||
MOVOU X11, 48(AX)
|
||||
|
||||
LEAQ 128(SI), SI
|
||||
SUBQ $128, DI
|
||||
JNE loop
|
||||
|
||||
MOVOU X12, 0(AX)
|
||||
MOVOU X15, 16(AX)
|
||||
|
||||
MOVQ R8, 0(BX)
|
||||
MOVQ R9, 8(BX)
|
||||
|
||||
MOVQ BP, SP
|
||||
RET
|
||||
|
||||
// func supportsSSE4() bool
|
||||
TEXT ·supportsSSE4(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
SHRL $19, CX // Bit 19 indicates SSE4 support
|
||||
ANDL $1, CX // CX != 0 if support SSE4
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
|
@ -0,0 +1,179 @@
|
|||
// 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 blake2b
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// the precomputed values for BLAKE2b
|
||||
// there are 12 16-byte arrays - one for each round
|
||||
// the entries are calculated from the sigma constants.
|
||||
var precomputed = [12][16]byte{
|
||||
{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15},
|
||||
{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3},
|
||||
{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4},
|
||||
{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8},
|
||||
{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13},
|
||||
{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9},
|
||||
{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11},
|
||||
{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10},
|
||||
{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5},
|
||||
{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0},
|
||||
{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, // equal to the first
|
||||
{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, // equal to the second
|
||||
}
|
||||
|
||||
func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
|
||||
var m [16]uint64
|
||||
c0, c1 := c[0], c[1]
|
||||
|
||||
for i := 0; i < len(blocks); {
|
||||
c0 += BlockSize
|
||||
if c0 < BlockSize {
|
||||
c1++
|
||||
}
|
||||
|
||||
v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
|
||||
v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]
|
||||
v12 ^= c0
|
||||
v13 ^= c1
|
||||
v14 ^= flag
|
||||
|
||||
for j := range m {
|
||||
m[j] = binary.LittleEndian.Uint64(blocks[i:])
|
||||
i += 8
|
||||
}
|
||||
|
||||
for j := range precomputed {
|
||||
s := &(precomputed[j])
|
||||
|
||||
v0 += m[s[0]]
|
||||
v0 += v4
|
||||
v12 ^= v0
|
||||
v12 = v12<<(64-32) | v12>>32
|
||||
v8 += v12
|
||||
v4 ^= v8
|
||||
v4 = v4<<(64-24) | v4>>24
|
||||
v1 += m[s[1]]
|
||||
v1 += v5
|
||||
v13 ^= v1
|
||||
v13 = v13<<(64-32) | v13>>32
|
||||
v9 += v13
|
||||
v5 ^= v9
|
||||
v5 = v5<<(64-24) | v5>>24
|
||||
v2 += m[s[2]]
|
||||
v2 += v6
|
||||
v14 ^= v2
|
||||
v14 = v14<<(64-32) | v14>>32
|
||||
v10 += v14
|
||||
v6 ^= v10
|
||||
v6 = v6<<(64-24) | v6>>24
|
||||
v3 += m[s[3]]
|
||||
v3 += v7
|
||||
v15 ^= v3
|
||||
v15 = v15<<(64-32) | v15>>32
|
||||
v11 += v15
|
||||
v7 ^= v11
|
||||
v7 = v7<<(64-24) | v7>>24
|
||||
|
||||
v0 += m[s[4]]
|
||||
v0 += v4
|
||||
v12 ^= v0
|
||||
v12 = v12<<(64-16) | v12>>16
|
||||
v8 += v12
|
||||
v4 ^= v8
|
||||
v4 = v4<<(64-63) | v4>>63
|
||||
v1 += m[s[5]]
|
||||
v1 += v5
|
||||
v13 ^= v1
|
||||
v13 = v13<<(64-16) | v13>>16
|
||||
v9 += v13
|
||||
v5 ^= v9
|
||||
v5 = v5<<(64-63) | v5>>63
|
||||
v2 += m[s[6]]
|
||||
v2 += v6
|
||||
v14 ^= v2
|
||||
v14 = v14<<(64-16) | v14>>16
|
||||
v10 += v14
|
||||
v6 ^= v10
|
||||
v6 = v6<<(64-63) | v6>>63
|
||||
v3 += m[s[7]]
|
||||
v3 += v7
|
||||
v15 ^= v3
|
||||
v15 = v15<<(64-16) | v15>>16
|
||||
v11 += v15
|
||||
v7 ^= v11
|
||||
v7 = v7<<(64-63) | v7>>63
|
||||
|
||||
v0 += m[s[8]]
|
||||
v0 += v5
|
||||
v15 ^= v0
|
||||
v15 = v15<<(64-32) | v15>>32
|
||||
v10 += v15
|
||||
v5 ^= v10
|
||||
v5 = v5<<(64-24) | v5>>24
|
||||
v1 += m[s[9]]
|
||||
v1 += v6
|
||||
v12 ^= v1
|
||||
v12 = v12<<(64-32) | v12>>32
|
||||
v11 += v12
|
||||
v6 ^= v11
|
||||
v6 = v6<<(64-24) | v6>>24
|
||||
v2 += m[s[10]]
|
||||
v2 += v7
|
||||
v13 ^= v2
|
||||
v13 = v13<<(64-32) | v13>>32
|
||||
v8 += v13
|
||||
v7 ^= v8
|
||||
v7 = v7<<(64-24) | v7>>24
|
||||
v3 += m[s[11]]
|
||||
v3 += v4
|
||||
v14 ^= v3
|
||||
v14 = v14<<(64-32) | v14>>32
|
||||
v9 += v14
|
||||
v4 ^= v9
|
||||
v4 = v4<<(64-24) | v4>>24
|
||||
|
||||
v0 += m[s[12]]
|
||||
v0 += v5
|
||||
v15 ^= v0
|
||||
v15 = v15<<(64-16) | v15>>16
|
||||
v10 += v15
|
||||
v5 ^= v10
|
||||
v5 = v5<<(64-63) | v5>>63
|
||||
v1 += m[s[13]]
|
||||
v1 += v6
|
||||
v12 ^= v1
|
||||
v12 = v12<<(64-16) | v12>>16
|
||||
v11 += v12
|
||||
v6 ^= v11
|
||||
v6 = v6<<(64-63) | v6>>63
|
||||
v2 += m[s[14]]
|
||||
v2 += v7
|
||||
v13 ^= v2
|
||||
v13 = v13<<(64-16) | v13>>16
|
||||
v8 += v13
|
||||
v7 ^= v8
|
||||
v7 = v7<<(64-63) | v7>>63
|
||||
v3 += m[s[15]]
|
||||
v3 += v4
|
||||
v14 ^= v3
|
||||
v14 = v14<<(64-16) | v14>>16
|
||||
v9 += v14
|
||||
v4 ^= v9
|
||||
v4 = v4<<(64-63) | v4>>63
|
||||
|
||||
}
|
||||
|
||||
h[0] ^= v0 ^ v8
|
||||
h[1] ^= v1 ^ v9
|
||||
h[2] ^= v2 ^ v10
|
||||
h[3] ^= v3 ^ v11
|
||||
h[4] ^= v4 ^ v12
|
||||
h[5] ^= v5 ^ v13
|
||||
h[6] ^= v6 ^ v14
|
||||
h[7] ^= v7 ^ v15
|
||||
}
|
||||
c[0], c[1] = c0, c1
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// 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.
|
||||
|
||||
// +build !amd64 appengine gccgo
|
||||
|
||||
package blake2b
|
||||
|
||||
func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) {
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
|
@ -0,0 +1,798 @@
|
|||
// 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 blake2b
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func fromHex(s string) []byte {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func TestHashes(t *testing.T) {
|
||||
defer func(sse4, avx, avx2 bool) {
|
||||
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
|
||||
}(useSSE4, useAVX, useAVX2)
|
||||
|
||||
if useAVX2 {
|
||||
t.Log("AVX2 version")
|
||||
testHashes(t)
|
||||
useAVX2 = false
|
||||
}
|
||||
if useAVX {
|
||||
t.Log("AVX version")
|
||||
testHashes(t)
|
||||
useAVX = false
|
||||
}
|
||||
if useSSE4 {
|
||||
t.Log("SSE4 version")
|
||||
testHashes(t)
|
||||
useSSE4 = false
|
||||
}
|
||||
t.Log("generic version")
|
||||
testHashes(t)
|
||||
}
|
||||
|
||||
func TestHashes2X(t *testing.T) {
|
||||
defer func(sse4, avx, avx2 bool) {
|
||||
useSSE4, useAVX, useAVX2 = sse4, avx, avx2
|
||||
}(useSSE4, useAVX, useAVX2)
|
||||
|
||||
if useAVX2 {
|
||||
t.Log("AVX2 version")
|
||||
testHashes2X(t)
|
||||
useAVX2 = false
|
||||
}
|
||||
if useAVX {
|
||||
t.Log("AVX version")
|
||||
testHashes2X(t)
|
||||
useAVX = false
|
||||
}
|
||||
if useSSE4 {
|
||||
t.Log("SSE4 version")
|
||||
testHashes2X(t)
|
||||
useSSE4 = false
|
||||
}
|
||||
t.Log("generic version")
|
||||
testHashes2X(t)
|
||||
}
|
||||
|
||||
func testHashes(t *testing.T) {
|
||||
key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")
|
||||
|
||||
input := make([]byte, 255)
|
||||
for i := range input {
|
||||
input[i] = byte(i)
|
||||
}
|
||||
|
||||
for i, expectedHex := range hashes {
|
||||
h, err := New512(key)
|
||||
if err != nil {
|
||||
t.Fatalf("#%d: error from New512: %v", i, err)
|
||||
}
|
||||
|
||||
h.Write(input[:i])
|
||||
sum := h.Sum(nil)
|
||||
|
||||
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
|
||||
t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
|
||||
}
|
||||
|
||||
h.Reset()
|
||||
for j := 0; j < i; j++ {
|
||||
h.Write(input[j : j+1])
|
||||
}
|
||||
|
||||
sum = h.Sum(sum[:0])
|
||||
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
|
||||
t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testHashes2X(t *testing.T) {
|
||||
key, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")
|
||||
|
||||
input := make([]byte, 256)
|
||||
for i := range input {
|
||||
input[i] = byte(i)
|
||||
}
|
||||
|
||||
for i, expectedHex := range hashes2X {
|
||||
length := uint32(len(expectedHex) / 2)
|
||||
sum := make([]byte, int(length))
|
||||
|
||||
h, err := NewXOF(length, key)
|
||||
if err != nil {
|
||||
t.Fatalf("#%d: error from NewXOF: %v", i, err)
|
||||
}
|
||||
|
||||
if _, err := h.Write(input); err != nil {
|
||||
t.Fatalf("#%d (single write): error from Write: %v", i, err)
|
||||
}
|
||||
if _, err := h.Read(sum); err != nil {
|
||||
t.Fatalf("#%d (single write): error from Read: %v", i, err)
|
||||
}
|
||||
if n, err := h.Read(sum); n != 0 || err != io.EOF {
|
||||
t.Fatalf("#%d (single write): Read did not return (0, os.EOF) after exhaustion, got (%v, %v)", i, n, err)
|
||||
}
|
||||
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
|
||||
t.Fatalf("#%d (single write): got %s, wanted %s", i, gotHex, expectedHex)
|
||||
}
|
||||
|
||||
h.Reset()
|
||||
for j := 0; j < len(input); j++ {
|
||||
h.Write(input[j : j+1])
|
||||
}
|
||||
for j := 0; j < len(sum); j++ {
|
||||
h = h.Clone()
|
||||
if _, err := h.Read(sum[j : j+1]); err != nil {
|
||||
t.Fatalf("#%d (byte-by-byte) - Read %d: error from Read: %v", i, j, err)
|
||||
}
|
||||
}
|
||||
if gotHex := fmt.Sprintf("%x", sum); gotHex != expectedHex {
|
||||
t.Fatalf("#%d (byte-by-byte): got %s, wanted %s", i, gotHex, expectedHex)
|
||||
}
|
||||
}
|
||||
|
||||
h, err := NewXOF(OutputLengthUnknown, key)
|
||||
if err != nil {
|
||||
t.Fatalf("#unknown length: error from NewXOF: %v", err)
|
||||
}
|
||||
if _, err := h.Write(input); err != nil {
|
||||
t.Fatalf("#unknown length: error from Write: %v", err)
|
||||
}
|
||||
|
||||
var result [64]byte
|
||||
if n, err := h.Read(result[:]); err != nil {
|
||||
t.Fatalf("#unknown length: error from Read: %v", err)
|
||||
} else if n != len(result) {
|
||||
t.Fatalf("#unknown length: Read returned %d bytes, want %d", n, len(result))
|
||||
}
|
||||
|
||||
const expected = "3dbba8516da76bf7330055c66ea36cf1005e92714262b24d9710f51d9e126406e1bcd6497059f9331f1091c3634b695428d475ed432f987040575520a1c29f5e"
|
||||
if fmt.Sprintf("%x", result) != expected {
|
||||
t.Fatalf("#unknown length: bad result %x, wanted %s", result, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func generateSequence(out []byte, seed uint32) {
|
||||
a := 0xDEAD4BAD * seed // prime
|
||||
b := uint32(1)
|
||||
|
||||
for i := range out { // fill the buf
|
||||
a, b = b, a+b
|
||||
out[i] = byte(b >> 24)
|
||||
}
|
||||
}
|
||||
|
||||
func computeMAC(msg []byte, hashSize int, key []byte) (sum []byte) {
|
||||
var h hash.Hash
|
||||
switch hashSize {
|
||||
case Size:
|
||||
h, _ = New512(key)
|
||||
case Size384:
|
||||
h, _ = New384(key)
|
||||
case Size256:
|
||||
h, _ = New256(key)
|
||||
case 20:
|
||||
h, _ = newDigest(20, key)
|
||||
default:
|
||||
panic("unexpected hashSize")
|
||||
}
|
||||
|
||||
h.Write(msg)
|
||||
return h.Sum(sum)
|
||||
}
|
||||
|
||||
func computeHash(msg []byte, hashSize int) (sum []byte) {
|
||||
switch hashSize {
|
||||
case Size:
|
||||
hash := Sum512(msg)
|
||||
return hash[:]
|
||||
case Size384:
|
||||
hash := Sum384(msg)
|
||||
return hash[:]
|
||||
case Size256:
|
||||
hash := Sum256(msg)
|
||||
return hash[:]
|
||||
case 20:
|
||||
var hash [64]byte
|
||||
checkSum(&hash, 20, msg)
|
||||
return hash[:20]
|
||||
default:
|
||||
panic("unexpected hashSize")
|
||||
}
|
||||
}
|
||||
|
||||
// Test function from RFC 7693.
|
||||
func TestSelfTest(t *testing.T) {
|
||||
hashLens := [4]int{20, 32, 48, 64}
|
||||
msgLens := [6]int{0, 3, 128, 129, 255, 1024}
|
||||
|
||||
msg := make([]byte, 1024)
|
||||
key := make([]byte, 64)
|
||||
|
||||
h, _ := New256(nil)
|
||||
for _, hashSize := range hashLens {
|
||||
for _, msgLength := range msgLens {
|
||||
generateSequence(msg[:msgLength], uint32(msgLength)) // unkeyed hash
|
||||
|
||||
md := computeHash(msg[:msgLength], hashSize)
|
||||
h.Write(md)
|
||||
|
||||
generateSequence(key[:], uint32(hashSize)) // keyed hash
|
||||
md = computeMAC(msg[:msgLength], hashSize, key[:hashSize])
|
||||
h.Write(md)
|
||||
}
|
||||
}
|
||||
|
||||
sum := h.Sum(nil)
|
||||
expected := [32]byte{
|
||||
0xc2, 0x3a, 0x78, 0x00, 0xd9, 0x81, 0x23, 0xbd,
|
||||
0x10, 0xf5, 0x06, 0xc6, 0x1e, 0x29, 0xda, 0x56,
|
||||
0x03, 0xd7, 0x63, 0xb8, 0xbb, 0xad, 0x2e, 0x73,
|
||||
0x7f, 0x5e, 0x76, 0x5a, 0x7b, 0xcc, 0xd4, 0x75,
|
||||
}
|
||||
if !bytes.Equal(sum, expected[:]) {
|
||||
t.Fatalf("got %x, wanted %x", sum, expected)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmarks
|
||||
|
||||
func benchmarkSum(b *testing.B, size int) {
|
||||
data := make([]byte, size)
|
||||
b.SetBytes(int64(size))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sum512(data)
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkWrite(b *testing.B, size int) {
|
||||
data := make([]byte, size)
|
||||
h, _ := New512(nil)
|
||||
b.SetBytes(int64(size))
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
h.Write(data)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWrite128(b *testing.B) { benchmarkWrite(b, 128) }
|
||||
func BenchmarkWrite1K(b *testing.B) { benchmarkWrite(b, 1024) }
|
||||
|
||||
func BenchmarkSum128(b *testing.B) { benchmarkSum(b, 128) }
|
||||
func BenchmarkSum1K(b *testing.B) { benchmarkSum(b, 1024) }
|
||||
|
||||
// These values were taken from https://blake2.net/blake2b-test.txt.
|
||||
var hashes = []string{
|
||||
"10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568",
|
||||
"961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd",
|
||||
"da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965",
|
||||
"33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1",
|
||||
"beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac",
|
||||
"098084b51fd13deae5f4320de94a688ee07baea2800486689a8636117b46c1f4c1f6af7f74ae7c857600456a58a3af251dc4723a64cc7c0a5ab6d9cac91c20bb",
|
||||
"6044540d560853eb1c57df0077dd381094781cdb9073e5b1b3d3f6c7829e12066bbaca96d989a690de72ca3133a83652ba284a6d62942b271ffa2620c9e75b1f",
|
||||
"7a8cfe9b90f75f7ecb3acc053aaed6193112b6f6a4aeeb3f65d3de541942deb9e2228152a3c4bbbe72fc3b12629528cfbb09fe630f0474339f54abf453e2ed52",
|
||||
"380beaf6ea7cc9365e270ef0e6f3a64fb902acae51dd5512f84259ad2c91f4bc4108db73192a5bbfb0cbcf71e46c3e21aee1c5e860dc96e8eb0b7b8426e6abe9",
|
||||
"60fe3c4535e1b59d9a61ea8500bfac41a69dffb1ceadd9aca323e9a625b64da5763bad7226da02b9c8c4f1a5de140ac5a6c1124e4f718ce0b28ea47393aa6637",
|
||||
"4fe181f54ad63a2983feaaf77d1e7235c2beb17fa328b6d9505bda327df19fc37f02c4b6f0368ce23147313a8e5738b5fa2a95b29de1c7f8264eb77b69f585cd",
|
||||
"f228773ce3f3a42b5f144d63237a72d99693adb8837d0e112a8a0f8ffff2c362857ac49c11ec740d1500749dac9b1f4548108bf3155794dcc9e4082849e2b85b",
|
||||
"962452a8455cc56c8511317e3b1f3b2c37df75f588e94325fdd77070359cf63a9ae6e930936fdf8e1e08ffca440cfb72c28f06d89a2151d1c46cd5b268ef8563",
|
||||
"43d44bfa18768c59896bf7ed1765cb2d14af8c260266039099b25a603e4ddc5039d6ef3a91847d1088d401c0c7e847781a8a590d33a3c6cb4df0fab1c2f22355",
|
||||
"dcffa9d58c2a4ca2cdbb0c7aa4c4c1d45165190089f4e983bb1c2cab4aaeff1fa2b5ee516fecd780540240bf37e56c8bcca7fab980e1e61c9400d8a9a5b14ac6",
|
||||
"6fbf31b45ab0c0b8dad1c0f5f4061379912dde5aa922099a030b725c73346c524291adef89d2f6fd8dfcda6d07dad811a9314536c2915ed45da34947e83de34e",
|
||||
"a0c65bddde8adef57282b04b11e7bc8aab105b99231b750c021f4a735cb1bcfab87553bba3abb0c3e64a0b6955285185a0bd35fb8cfde557329bebb1f629ee93",
|
||||
"f99d815550558e81eca2f96718aed10d86f3f1cfb675cce06b0eff02f617c5a42c5aa760270f2679da2677c5aeb94f1142277f21c7f79f3c4f0cce4ed8ee62b1",
|
||||
"95391da8fc7b917a2044b3d6f5374e1ca072b41454d572c7356c05fd4bc1e0f40b8bb8b4a9f6bce9be2c4623c399b0dca0dab05cb7281b71a21b0ebcd9e55670",
|
||||
"04b9cd3d20d221c09ac86913d3dc63041989a9a1e694f1e639a3ba7e451840f750c2fc191d56ad61f2e7936bc0ac8e094b60caeed878c18799045402d61ceaf9",
|
||||
"ec0e0ef707e4ed6c0c66f9e089e4954b058030d2dd86398fe84059631f9ee591d9d77375355149178c0cf8f8e7c49ed2a5e4f95488a2247067c208510fadc44c",
|
||||
"9a37cce273b79c09913677510eaf7688e89b3314d3532fd2764c39de022a2945b5710d13517af8ddc0316624e73bec1ce67df15228302036f330ab0cb4d218dd",
|
||||
"4cf9bb8fb3d4de8b38b2f262d3c40f46dfe747e8fc0a414c193d9fcf753106ce47a18f172f12e8a2f1c26726545358e5ee28c9e2213a8787aafbc516d2343152",
|
||||
"64e0c63af9c808fd893137129867fd91939d53f2af04be4fa268006100069b2d69daa5c5d8ed7fddcb2a70eeecdf2b105dd46a1e3b7311728f639ab489326bc9",
|
||||
"5e9c93158d659b2def06b0c3c7565045542662d6eee8a96a89b78ade09fe8b3dcc096d4fe48815d88d8f82620156602af541955e1f6ca30dce14e254c326b88f",
|
||||
"7775dff889458dd11aef417276853e21335eb88e4dec9cfb4e9edb49820088551a2ca60339f12066101169f0dfe84b098fddb148d9da6b3d613df263889ad64b",
|
||||
"f0d2805afbb91f743951351a6d024f9353a23c7ce1fc2b051b3a8b968c233f46f50f806ecb1568ffaa0b60661e334b21dde04f8fa155ac740eeb42e20b60d764",
|
||||
"86a2af316e7d7754201b942e275364ac12ea8962ab5bd8d7fb276dc5fbffc8f9a28cae4e4867df6780d9b72524160927c855da5b6078e0b554aa91e31cb9ca1d",
|
||||
"10bdf0caa0802705e706369baf8a3f79d72c0a03a80675a7bbb00be3a45e516424d1ee88efb56f6d5777545ae6e27765c3a8f5e493fc308915638933a1dfee55",
|
||||
"b01781092b1748459e2e4ec178696627bf4ebafebba774ecf018b79a68aeb84917bf0b84bb79d17b743151144cd66b7b33a4b9e52c76c4e112050ff5385b7f0b",
|
||||
"c6dbc61dec6eaeac81e3d5f755203c8e220551534a0b2fd105a91889945a638550204f44093dd998c076205dffad703a0e5cd3c7f438a7e634cd59fededb539e",
|
||||
"eba51acffb4cea31db4b8d87e9bf7dd48fe97b0253ae67aa580f9ac4a9d941f2bea518ee286818cc9f633f2a3b9fb68e594b48cdd6d515bf1d52ba6c85a203a7",
|
||||
"86221f3ada52037b72224f105d7999231c5e5534d03da9d9c0a12acb68460cd375daf8e24386286f9668f72326dbf99ba094392437d398e95bb8161d717f8991",
|
||||
"5595e05c13a7ec4dc8f41fb70cb50a71bce17c024ff6de7af618d0cc4e9c32d9570d6d3ea45b86525491030c0d8f2b1836d5778c1ce735c17707df364d054347",
|
||||
"ce0f4f6aca89590a37fe034dd74dd5fa65eb1cbd0a41508aaddc09351a3cea6d18cb2189c54b700c009f4cbf0521c7ea01be61c5ae09cb54f27bc1b44d658c82",
|
||||
"7ee80b06a215a3bca970c77cda8761822bc103d44fa4b33f4d07dcb997e36d55298bceae12241b3fa07fa63be5576068da387b8d5859aeab701369848b176d42",
|
||||
"940a84b6a84d109aab208c024c6ce9647676ba0aaa11f86dbb7018f9fd2220a6d901a9027f9abcf935372727cbf09ebd61a2a2eeb87653e8ecad1bab85dc8327",
|
||||
"2020b78264a82d9f4151141adba8d44bf20c5ec062eee9b595a11f9e84901bf148f298e0c9f8777dcdbc7cc4670aac356cc2ad8ccb1629f16f6a76bcefbee760",
|
||||
"d1b897b0e075ba68ab572adf9d9c436663e43eb3d8e62d92fc49c9be214e6f27873fe215a65170e6bea902408a25b49506f47babd07cecf7113ec10c5dd31252",
|
||||
"b14d0c62abfa469a357177e594c10c194243ed2025ab8aa5ad2fa41ad318e0ff48cd5e60bec07b13634a711d2326e488a985f31e31153399e73088efc86a5c55",
|
||||
"4169c5cc808d2697dc2a82430dc23e3cd356dc70a94566810502b8d655b39abf9e7f902fe717e0389219859e1945df1af6ada42e4ccda55a197b7100a30c30a1",
|
||||
"258a4edb113d66c839c8b1c91f15f35ade609f11cd7f8681a4045b9fef7b0b24c82cda06a5f2067b368825e3914e53d6948ede92efd6e8387fa2e537239b5bee",
|
||||
"79d2d8696d30f30fb34657761171a11e6c3f1e64cbe7bebee159cb95bfaf812b4f411e2f26d9c421dc2c284a3342d823ec293849e42d1e46b0a4ac1e3c86abaa",
|
||||
"8b9436010dc5dee992ae38aea97f2cd63b946d94fedd2ec9671dcde3bd4ce9564d555c66c15bb2b900df72edb6b891ebcadfeff63c9ea4036a998be7973981e7",
|
||||
"c8f68e696ed28242bf997f5b3b34959508e42d613810f1e2a435c96ed2ff560c7022f361a9234b9837feee90bf47922ee0fd5f8ddf823718d86d1e16c6090071",
|
||||
"b02d3eee4860d5868b2c39ce39bfe81011290564dd678c85e8783f29302dfc1399ba95b6b53cd9ebbf400cca1db0ab67e19a325f2d115812d25d00978ad1bca4",
|
||||
"7693ea73af3ac4dad21ca0d8da85b3118a7d1c6024cfaf557699868217bc0c2f44a199bc6c0edd519798ba05bd5b1b4484346a47c2cadf6bf30b785cc88b2baf",
|
||||
"a0e5c1c0031c02e48b7f09a5e896ee9aef2f17fc9e18e997d7f6cac7ae316422c2b1e77984e5f3a73cb45deed5d3f84600105e6ee38f2d090c7d0442ea34c46d",
|
||||
"41daa6adcfdb69f1440c37b596440165c15ada596813e2e22f060fcd551f24dee8e04ba6890387886ceec4a7a0d7fc6b44506392ec3822c0d8c1acfc7d5aebe8",
|
||||
"14d4d40d5984d84c5cf7523b7798b254e275a3a8cc0a1bd06ebc0bee726856acc3cbf516ff667cda2058ad5c3412254460a82c92187041363cc77a4dc215e487",
|
||||
"d0e7a1e2b9a447fee83e2277e9ff8010c2f375ae12fa7aaa8ca5a6317868a26a367a0b69fbc1cf32a55d34eb370663016f3d2110230eba754028a56f54acf57c",
|
||||
"e771aa8db5a3e043e8178f39a0857ba04a3f18e4aa05743cf8d222b0b095825350ba422f63382a23d92e4149074e816a36c1cd28284d146267940b31f8818ea2",
|
||||
"feb4fd6f9e87a56bef398b3284d2bda5b5b0e166583a66b61e538457ff0584872c21a32962b9928ffab58de4af2edd4e15d8b35570523207ff4e2a5aa7754caa",
|
||||
"462f17bf005fb1c1b9e671779f665209ec2873e3e411f98dabf240a1d5ec3f95ce6796b6fc23fe171903b502023467dec7273ff74879b92967a2a43a5a183d33",
|
||||
"d3338193b64553dbd38d144bea71c5915bb110e2d88180dbc5db364fd6171df317fc7268831b5aef75e4342b2fad8797ba39eddcef80e6ec08159350b1ad696d",
|
||||
"e1590d585a3d39f7cb599abd479070966409a6846d4377acf4471d065d5db94129cc9be92573b05ed226be1e9b7cb0cabe87918589f80dadd4ef5ef25a93d28e",
|
||||
"f8f3726ac5a26cc80132493a6fedcb0e60760c09cfc84cad178175986819665e76842d7b9fedf76dddebf5d3f56faaad4477587af21606d396ae570d8e719af2",
|
||||
"30186055c07949948183c850e9a756cc09937e247d9d928e869e20bafc3cd9721719d34e04a0899b92c736084550186886efba2e790d8be6ebf040b209c439a4",
|
||||
"f3c4276cb863637712c241c444c5cc1e3554e0fddb174d035819dd83eb700b4ce88df3ab3841ba02085e1a99b4e17310c5341075c0458ba376c95a6818fbb3e2",
|
||||
"0aa007c4dd9d5832393040a1583c930bca7dc5e77ea53add7e2b3f7c8e231368043520d4a3ef53c969b6bbfd025946f632bd7f765d53c21003b8f983f75e2a6a",
|
||||
"08e9464720533b23a04ec24f7ae8c103145f765387d738777d3d343477fd1c58db052142cab754ea674378e18766c53542f71970171cc4f81694246b717d7564",
|
||||
"d37ff7ad297993e7ec21e0f1b4b5ae719cdc83c5db687527f27516cbffa822888a6810ee5c1ca7bfe3321119be1ab7bfa0a502671c8329494df7ad6f522d440f",
|
||||
"dd9042f6e464dcf86b1262f6accfafbd8cfd902ed3ed89abf78ffa482dbdeeb6969842394c9a1168ae3d481a017842f660002d42447c6b22f7b72f21aae021c9",
|
||||
"bd965bf31e87d70327536f2a341cebc4768eca275fa05ef98f7f1b71a0351298de006fba73fe6733ed01d75801b4a928e54231b38e38c562b2e33ea1284992fa",
|
||||
"65676d800617972fbd87e4b9514e1c67402b7a331096d3bfac22f1abb95374abc942f16e9ab0ead33b87c91968a6e509e119ff07787b3ef483e1dcdccf6e3022",
|
||||
"939fa189699c5d2c81ddd1ffc1fa207c970b6a3685bb29ce1d3e99d42f2f7442da53e95a72907314f4588399a3ff5b0a92beb3f6be2694f9f86ecf2952d5b41c",
|
||||
"c516541701863f91005f314108ceece3c643e04fc8c42fd2ff556220e616aaa6a48aeb97a84bad74782e8dff96a1a2fa949339d722edcaa32b57067041df88cc",
|
||||
"987fd6e0d6857c553eaebb3d34970a2c2f6e89a3548f492521722b80a1c21a153892346d2cba6444212d56da9a26e324dccbc0dcde85d4d2ee4399eec5a64e8f",
|
||||
"ae56deb1c2328d9c4017706bce6e99d41349053ba9d336d677c4c27d9fd50ae6aee17e853154e1f4fe7672346da2eaa31eea53fcf24a22804f11d03da6abfc2b",
|
||||
"49d6a608c9bde4491870498572ac31aac3fa40938b38a7818f72383eb040ad39532bc06571e13d767e6945ab77c0bdc3b0284253343f9f6c1244ebf2ff0df866",
|
||||
"da582ad8c5370b4469af862aa6467a2293b2b28bd80ae0e91f425ad3d47249fdf98825cc86f14028c3308c9804c78bfeeeee461444ce243687e1a50522456a1d",
|
||||
"d5266aa3331194aef852eed86d7b5b2633a0af1c735906f2e13279f14931a9fc3b0eac5ce9245273bd1aa92905abe16278ef7efd47694789a7283b77da3c70f8",
|
||||
"2962734c28252186a9a1111c732ad4de4506d4b4480916303eb7991d659ccda07a9911914bc75c418ab7a4541757ad054796e26797feaf36e9f6ad43f14b35a4",
|
||||
"e8b79ec5d06e111bdfafd71e9f5760f00ac8ac5d8bf768f9ff6f08b8f026096b1cc3a4c973333019f1e3553e77da3f98cb9f542e0a90e5f8a940cc58e59844b3",
|
||||
"dfb320c44f9d41d1efdcc015f08dd5539e526e39c87d509ae6812a969e5431bf4fa7d91ffd03b981e0d544cf72d7b1c0374f8801482e6dea2ef903877eba675e",
|
||||
"d88675118fdb55a5fb365ac2af1d217bf526ce1ee9c94b2f0090b2c58a06ca58187d7fe57c7bed9d26fca067b4110eefcd9a0a345de872abe20de368001b0745",
|
||||
"b893f2fc41f7b0dd6e2f6aa2e0370c0cff7df09e3acfcc0e920b6e6fad0ef747c40668417d342b80d2351e8c175f20897a062e9765e6c67b539b6ba8b9170545",
|
||||
"6c67ec5697accd235c59b486d7b70baeedcbd4aa64ebd4eef3c7eac189561a726250aec4d48cadcafbbe2ce3c16ce2d691a8cce06e8879556d4483ed7165c063",
|
||||
"f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd",
|
||||
"cbaa259572d4aebfc1917acddc582b9f8dfaa928a198ca7acd0f2aa76a134a90252e6298a65b08186a350d5b7626699f8cb721a3ea5921b753ae3a2dce24ba3a",
|
||||
"fa1549c9796cd4d303dcf452c1fbd5744fd9b9b47003d920b92de34839d07ef2a29ded68f6fc9e6c45e071a2e48bd50c5084e96b657dd0404045a1ddefe282ed",
|
||||
"5cf2ac897ab444dcb5c8d87c495dbdb34e1838b6b629427caa51702ad0f9688525f13bec503a3c3a2c80a65e0b5715e8afab00ffa56ec455a49a1ad30aa24fcd",
|
||||
"9aaf80207bace17bb7ab145757d5696bde32406ef22b44292ef65d4519c3bb2ad41a59b62cc3e94b6fa96d32a7faadae28af7d35097219aa3fd8cda31e40c275",
|
||||
"af88b163402c86745cb650c2988fb95211b94b03ef290eed9662034241fd51cf398f8073e369354c43eae1052f9b63b08191caa138aa54fea889cc7024236897",
|
||||
"48fa7d64e1ceee27b9864db5ada4b53d00c9bc7626555813d3cd6730ab3cc06ff342d727905e33171bde6e8476e77fb1720861e94b73a2c538d254746285f430",
|
||||
"0e6fd97a85e904f87bfe85bbeb34f69e1f18105cf4ed4f87aec36c6e8b5f68bd2a6f3dc8a9ecb2b61db4eedb6b2ea10bf9cb0251fb0f8b344abf7f366b6de5ab",
|
||||
"06622da5787176287fdc8fed440bad187d830099c94e6d04c8e9c954cda70c8bb9e1fc4a6d0baa831b9b78ef6648681a4867a11da93ee36e5e6a37d87fc63f6f",
|
||||
"1da6772b58fabf9c61f68d412c82f182c0236d7d575ef0b58dd22458d643cd1dfc93b03871c316d8430d312995d4197f0874c99172ba004a01ee295abac24e46",
|
||||
"3cd2d9320b7b1d5fb9aab951a76023fa667be14a9124e394513918a3f44096ae4904ba0ffc150b63bc7ab1eeb9a6e257e5c8f000a70394a5afd842715de15f29",
|
||||
"04cdc14f7434e0b4be70cb41db4c779a88eaef6accebcb41f2d42fffe7f32a8e281b5c103a27021d0d08362250753cdf70292195a53a48728ceb5844c2d98bab",
|
||||
"9071b7a8a075d0095b8fb3ae5113785735ab98e2b52faf91d5b89e44aac5b5d4ebbf91223b0ff4c71905da55342e64655d6ef8c89a4768c3f93a6dc0366b5bc8",
|
||||
"ebb30240dd96c7bc8d0abe49aa4edcbb4afdc51ff9aaf720d3f9e7fbb0f9c6d6571350501769fc4ebd0b2141247ff400d4fd4be414edf37757bb90a32ac5c65a",
|
||||
"8532c58bf3c8015d9d1cbe00eef1f5082f8f3632fbe9f1ed4f9dfb1fa79e8283066d77c44c4af943d76b300364aecbd0648c8a8939bd204123f4b56260422dec",
|
||||
"fe9846d64f7c7708696f840e2d76cb4408b6595c2f81ec6a28a7f2f20cb88cfe6ac0b9e9b8244f08bd7095c350c1d0842f64fb01bb7f532dfcd47371b0aeeb79",
|
||||
"28f17ea6fb6c42092dc264257e29746321fb5bdaea9873c2a7fa9d8f53818e899e161bc77dfe8090afd82bf2266c5c1bc930a8d1547624439e662ef695f26f24",
|
||||
"ec6b7d7f030d4850acae3cb615c21dd25206d63e84d1db8d957370737ba0e98467ea0ce274c66199901eaec18a08525715f53bfdb0aacb613d342ebdceeddc3b",
|
||||
"b403d3691c03b0d3418df327d5860d34bbfcc4519bfbce36bf33b208385fadb9186bc78a76c489d89fd57e7dc75412d23bcd1dae8470ce9274754bb8585b13c5",
|
||||
"31fc79738b8772b3f55cd8178813b3b52d0db5a419d30ba9495c4b9da0219fac6df8e7c23a811551a62b827f256ecdb8124ac8a6792ccfecc3b3012722e94463",
|
||||
"bb2039ec287091bcc9642fc90049e73732e02e577e2862b32216ae9bedcd730c4c284ef3968c368b7d37584f97bd4b4dc6ef6127acfe2e6ae2509124e66c8af4",
|
||||
"f53d68d13f45edfcb9bd415e2831e938350d5380d3432278fc1c0c381fcb7c65c82dafe051d8c8b0d44e0974a0e59ec7bf7ed0459f86e96f329fc79752510fd3",
|
||||
"8d568c7984f0ecdf7640fbc483b5d8c9f86634f6f43291841b309a350ab9c1137d24066b09da9944bac54d5bb6580d836047aac74ab724b887ebf93d4b32eca9",
|
||||
"c0b65ce5a96ff774c456cac3b5f2c4cd359b4ff53ef93a3da0778be4900d1e8da1601e769e8f1b02d2a2f8c5b9fa10b44f1c186985468feeb008730283a6657d",
|
||||
"4900bba6f5fb103ece8ec96ada13a5c3c85488e05551da6b6b33d988e611ec0fe2e3c2aa48ea6ae8986a3a231b223c5d27cec2eadde91ce07981ee652862d1e4",
|
||||
"c7f5c37c7285f927f76443414d4357ff789647d7a005a5a787e03c346b57f49f21b64fa9cf4b7e45573e23049017567121a9c3d4b2b73ec5e9413577525db45a",
|
||||
"ec7096330736fdb2d64b5653e7475da746c23a4613a82687a28062d3236364284ac01720ffb406cfe265c0df626a188c9e5963ace5d3d5bb363e32c38c2190a6",
|
||||
"82e744c75f4649ec52b80771a77d475a3bc091989556960e276a5f9ead92a03f718742cdcfeaee5cb85c44af198adc43a4a428f5f0c2ddb0be36059f06d7df73",
|
||||
"2834b7a7170f1f5b68559ab78c1050ec21c919740b784a9072f6e5d69f828d70c919c5039fb148e39e2c8a52118378b064ca8d5001cd10a5478387b966715ed6",
|
||||
"16b4ada883f72f853bb7ef253efcab0c3e2161687ad61543a0d2824f91c1f81347d86be709b16996e17f2dd486927b0288ad38d13063c4a9672c39397d3789b6",
|
||||
"78d048f3a69d8b54ae0ed63a573ae350d89f7c6cf1f3688930de899afa037697629b314e5cd303aa62feea72a25bf42b304b6c6bcb27fae21c16d925e1fbdac3",
|
||||
"0f746a48749287ada77a82961f05a4da4abdb7d77b1220f836d09ec814359c0ec0239b8c7b9ff9e02f569d1b301ef67c4612d1de4f730f81c12c40cc063c5caa",
|
||||
"f0fc859d3bd195fbdc2d591e4cdac15179ec0f1dc821c11df1f0c1d26e6260aaa65b79fafacafd7d3ad61e600f250905f5878c87452897647a35b995bcadc3a3",
|
||||
"2620f687e8625f6a412460b42e2cef67634208ce10a0cbd4dff7044a41b7880077e9f8dc3b8d1216d3376a21e015b58fb279b521d83f9388c7382c8505590b9b",
|
||||
"227e3aed8d2cb10b918fcb04f9de3e6d0a57e08476d93759cd7b2ed54a1cbf0239c528fb04bbf288253e601d3bc38b21794afef90b17094a182cac557745e75f",
|
||||
"1a929901b09c25f27d6b35be7b2f1c4745131fdebca7f3e2451926720434e0db6e74fd693ad29b777dc3355c592a361c4873b01133a57c2e3b7075cbdb86f4fc",
|
||||
"5fd7968bc2fe34f220b5e3dc5af9571742d73b7d60819f2888b629072b96a9d8ab2d91b82d0a9aaba61bbd39958132fcc4257023d1eca591b3054e2dc81c8200",
|
||||
"dfcce8cf32870cc6a503eadafc87fd6f78918b9b4d0737db6810be996b5497e7e5cc80e312f61e71ff3e9624436073156403f735f56b0b01845c18f6caf772e6",
|
||||
"02f7ef3a9ce0fff960f67032b296efca3061f4934d690749f2d01c35c81c14f39a67fa350bc8a0359bf1724bffc3bca6d7c7bba4791fd522a3ad353c02ec5aa8",
|
||||
"64be5c6aba65d594844ae78bb022e5bebe127fd6b6ffa5a13703855ab63b624dcd1a363f99203f632ec386f3ea767fc992e8ed9686586aa27555a8599d5b808f",
|
||||
"f78585505c4eaa54a8b5be70a61e735e0ff97af944ddb3001e35d86c4e2199d976104b6ae31750a36a726ed285064f5981b503889fef822fcdc2898dddb7889a",
|
||||
"e4b5566033869572edfd87479a5bb73c80e8759b91232879d96b1dda36c012076ee5a2ed7ae2de63ef8406a06aea82c188031b560beafb583fb3de9e57952a7e",
|
||||
"e1b3e7ed867f6c9484a2a97f7715f25e25294e992e41f6a7c161ffc2adc6daaeb7113102d5e6090287fe6ad94ce5d6b739c6ca240b05c76fb73f25dd024bf935",
|
||||
"85fd085fdc12a080983df07bd7012b0d402a0f4043fcb2775adf0bad174f9b08d1676e476985785c0a5dcc41dbff6d95ef4d66a3fbdc4a74b82ba52da0512b74",
|
||||
"aed8fa764b0fbff821e05233d2f7b0900ec44d826f95e93c343c1bc3ba5a24374b1d616e7e7aba453a0ada5e4fab5382409e0d42ce9c2bc7fb39a99c340c20f0",
|
||||
"7ba3b2e297233522eeb343bd3ebcfd835a04007735e87f0ca300cbee6d416565162171581e4020ff4cf176450f1291ea2285cb9ebffe4c56660627685145051c",
|
||||
"de748bcf89ec88084721e16b85f30adb1a6134d664b5843569babc5bbd1a15ca9b61803c901a4fef32965a1749c9f3a4e243e173939dc5a8dc495c671ab52145",
|
||||
"aaf4d2bdf200a919706d9842dce16c98140d34bc433df320aba9bd429e549aa7a3397652a4d768277786cf993cde2338673ed2e6b66c961fefb82cd20c93338f",
|
||||
"c408218968b788bf864f0997e6bc4c3dba68b276e2125a4843296052ff93bf5767b8cdce7131f0876430c1165fec6c4f47adaa4fd8bcfacef463b5d3d0fa61a0",
|
||||
"76d2d819c92bce55fa8e092ab1bf9b9eab237a25267986cacf2b8ee14d214d730dc9a5aa2d7b596e86a1fd8fa0804c77402d2fcd45083688b218b1cdfa0dcbcb",
|
||||
"72065ee4dd91c2d8509fa1fc28a37c7fc9fa7d5b3f8ad3d0d7a25626b57b1b44788d4caf806290425f9890a3a2a35a905ab4b37acfd0da6e4517b2525c9651e4",
|
||||
"64475dfe7600d7171bea0b394e27c9b00d8e74dd1e416a79473682ad3dfdbb706631558055cfc8a40e07bd015a4540dcdea15883cbbf31412df1de1cd4152b91",
|
||||
"12cd1674a4488a5d7c2b3160d2e2c4b58371bedad793418d6f19c6ee385d70b3e06739369d4df910edb0b0a54cbff43d54544cd37ab3a06cfa0a3ddac8b66c89",
|
||||
"60756966479dedc6dd4bcff8ea7d1d4ce4d4af2e7b097e32e3763518441147cc12b3c0ee6d2ecabf1198cec92e86a3616fba4f4e872f5825330adbb4c1dee444",
|
||||
"a7803bcb71bc1d0f4383dde1e0612e04f872b715ad30815c2249cf34abb8b024915cb2fc9f4e7cc4c8cfd45be2d5a91eab0941c7d270e2da4ca4a9f7ac68663a",
|
||||
"b84ef6a7229a34a750d9a98ee2529871816b87fbe3bc45b45fa5ae82d5141540211165c3c5d7a7476ba5a4aa06d66476f0d9dc49a3f1ee72c3acabd498967414",
|
||||
"fae4b6d8efc3f8c8e64d001dabec3a21f544e82714745251b2b4b393f2f43e0da3d403c64db95a2cb6e23ebb7b9e94cdd5ddac54f07c4a61bd3cb10aa6f93b49",
|
||||
"34f7286605a122369540141ded79b8957255da2d4155abbf5a8dbb89c8eb7ede8eeef1daa46dc29d751d045dc3b1d658bb64b80ff8589eddb3824b13da235a6b",
|
||||
"3b3b48434be27b9eababba43bf6b35f14b30f6a88dc2e750c358470d6b3aa3c18e47db4017fa55106d8252f016371a00f5f8b070b74ba5f23cffc5511c9f09f0",
|
||||
"ba289ebd6562c48c3e10a8ad6ce02e73433d1e93d7c9279d4d60a7e879ee11f441a000f48ed9f7c4ed87a45136d7dccdca482109c78a51062b3ba4044ada2469",
|
||||
"022939e2386c5a37049856c850a2bb10a13dfea4212b4c732a8840a9ffa5faf54875c5448816b2785a007da8a8d2bc7d71a54e4e6571f10b600cbdb25d13ede3",
|
||||
"e6fec19d89ce8717b1a087024670fe026f6c7cbda11caef959bb2d351bf856f8055d1c0ebdaaa9d1b17886fc2c562b5e99642fc064710c0d3488a02b5ed7f6fd",
|
||||
"94c96f02a8f576aca32ba61c2b206f907285d9299b83ac175c209a8d43d53bfe683dd1d83e7549cb906c28f59ab7c46f8751366a28c39dd5fe2693c9019666c8",
|
||||
"31a0cd215ebd2cb61de5b9edc91e6195e31c59a5648d5c9f737e125b2605708f2e325ab3381c8dce1a3e958886f1ecdc60318f882cfe20a24191352e617b0f21",
|
||||
"91ab504a522dce78779f4c6c6ba2e6b6db5565c76d3e7e7c920caf7f757ef9db7c8fcf10e57f03379ea9bf75eb59895d96e149800b6aae01db778bb90afbc989",
|
||||
"d85cabc6bd5b1a01a5afd8c6734740da9fd1c1acc6db29bfc8a2e5b668b028b6b3154bfb8703fa3180251d589ad38040ceb707c4bad1b5343cb426b61eaa49c1",
|
||||
"d62efbec2ca9c1f8bd66ce8b3f6a898cb3f7566ba6568c618ad1feb2b65b76c3ce1dd20f7395372faf28427f61c9278049cf0140df434f5633048c86b81e0399",
|
||||
"7c8fdc6175439e2c3db15bafa7fb06143a6a23bc90f449e79deef73c3d492a671715c193b6fea9f036050b946069856b897e08c00768f5ee5ddcf70b7cd6d0e0",
|
||||
"58602ee7468e6bc9df21bd51b23c005f72d6cb013f0a1b48cbec5eca299299f97f09f54a9a01483eaeb315a6478bad37ba47ca1347c7c8fc9e6695592c91d723",
|
||||
"27f5b79ed256b050993d793496edf4807c1d85a7b0a67c9c4fa99860750b0ae66989670a8ffd7856d7ce411599e58c4d77b232a62bef64d15275be46a68235ff",
|
||||
"3957a976b9f1887bf004a8dca942c92d2b37ea52600f25e0c9bc5707d0279c00c6e85a839b0d2d8eb59c51d94788ebe62474a791cadf52cccf20f5070b6573fc",
|
||||
"eaa2376d55380bf772ecca9cb0aa4668c95c707162fa86d518c8ce0ca9bf7362b9f2a0adc3ff59922df921b94567e81e452f6c1a07fc817cebe99604b3505d38",
|
||||
"c1e2c78b6b2734e2480ec550434cb5d613111adcc21d475545c3b1b7e6ff12444476e5c055132e2229dc0f807044bb919b1a5662dd38a9ee65e243a3911aed1a",
|
||||
"8ab48713389dd0fcf9f965d3ce66b1e559a1f8c58741d67683cd971354f452e62d0207a65e436c5d5d8f8ee71c6abfe50e669004c302b31a7ea8311d4a916051",
|
||||
"24ce0addaa4c65038bd1b1c0f1452a0b128777aabc94a29df2fd6c7e2f85f8ab9ac7eff516b0e0a825c84a24cfe492eaad0a6308e46dd42fe8333ab971bb30ca",
|
||||
"5154f929ee03045b6b0c0004fa778edee1d139893267cc84825ad7b36c63de32798e4a166d24686561354f63b00709a1364b3c241de3febf0754045897467cd4",
|
||||
"e74e907920fd87bd5ad636dd11085e50ee70459c443e1ce5809af2bc2eba39f9e6d7128e0e3712c316da06f4705d78a4838e28121d4344a2c79c5e0db307a677",
|
||||
"bf91a22334bac20f3fd80663b3cd06c4e8802f30e6b59f90d3035cc9798a217ed5a31abbda7fa6842827bdf2a7a1c21f6fcfccbb54c6c52926f32da816269be1",
|
||||
"d9d5c74be5121b0bd742f26bffb8c89f89171f3f934913492b0903c271bbe2b3395ef259669bef43b57f7fcc3027db01823f6baee66e4f9fead4d6726c741fce",
|
||||
"50c8b8cf34cd879f80e2faab3230b0c0e1cc3e9dcadeb1b9d97ab923415dd9a1fe38addd5c11756c67990b256e95ad6d8f9fedce10bf1c90679cde0ecf1be347",
|
||||
"0a386e7cd5dd9b77a035e09fe6fee2c8ce61b5383c87ea43205059c5e4cd4f4408319bb0a82360f6a58e6c9ce3f487c446063bf813bc6ba535e17fc1826cfc91",
|
||||
"1f1459cb6b61cbac5f0efe8fc487538f42548987fcd56221cfa7beb22504769e792c45adfb1d6b3d60d7b749c8a75b0bdf14e8ea721b95dca538ca6e25711209",
|
||||
"e58b3836b7d8fedbb50ca5725c6571e74c0785e97821dab8b6298c10e4c079d4a6cdf22f0fedb55032925c16748115f01a105e77e00cee3d07924dc0d8f90659",
|
||||
"b929cc6505f020158672deda56d0db081a2ee34c00c1100029bdf8ea98034fa4bf3e8655ec697fe36f40553c5bb46801644a627d3342f4fc92b61f03290fb381",
|
||||
"72d353994b49d3e03153929a1e4d4f188ee58ab9e72ee8e512f29bc773913819ce057ddd7002c0433ee0a16114e3d156dd2c4a7e80ee53378b8670f23e33ef56",
|
||||
"c70ef9bfd775d408176737a0736d68517ce1aaad7e81a93c8c1ed967ea214f56c8a377b1763e676615b60f3988241eae6eab9685a5124929d28188f29eab06f7",
|
||||
"c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f",
|
||||
"6f43094cafb5ebf1f7a4937ec50f56a4c9da303cbb55ac1f27f1f1976cd96beda9464f0e7b9c54620b8a9fba983164b8be3578425a024f5fe199c36356b88972",
|
||||
"3745273f4c38225db2337381871a0c6aafd3af9b018c88aa02025850a5dc3a42a1a3e03e56cbf1b0876d63a441f1d2856a39b8801eb5af325201c415d65e97fe",
|
||||
"c50c44cca3ec3edaae779a7e179450ebdda2f97067c690aa6c5a4ac7c30139bb27c0df4db3220e63cb110d64f37ffe078db72653e2daacf93ae3f0a2d1a7eb2e",
|
||||
"8aef263e385cbc61e19b28914243262af5afe8726af3ce39a79c27028cf3ecd3f8d2dfd9cfc9ad91b58f6f20778fd5f02894a3d91c7d57d1e4b866a7f364b6be",
|
||||
"28696141de6e2d9bcb3235578a66166c1448d3e905a1b482d423be4bc5369bc8c74dae0acc9cc123e1d8ddce9f97917e8c019c552da32d39d2219b9abf0fa8c8",
|
||||
"2fb9eb2085830181903a9dafe3db428ee15be7662224efd643371fb25646aee716e531eca69b2bdc8233f1a8081fa43da1500302975a77f42fa592136710e9dc",
|
||||
"66f9a7143f7a3314a669bf2e24bbb35014261d639f495b6c9c1f104fe8e320aca60d4550d69d52edbd5a3cdeb4014ae65b1d87aa770b69ae5c15f4330b0b0ad8",
|
||||
"f4c4dd1d594c3565e3e25ca43dad82f62abea4835ed4cd811bcd975e46279828d44d4c62c3679f1b7f7b9dd4571d7b49557347b8c5460cbdc1bef690fb2a08c0",
|
||||
"8f1dc9649c3a84551f8f6e91cac68242a43b1f8f328ee92280257387fa7559aa6db12e4aeadc2d26099178749c6864b357f3f83b2fb3efa8d2a8db056bed6bcc",
|
||||
"3139c1a7f97afd1675d460ebbc07f2728aa150df849624511ee04b743ba0a833092f18c12dc91b4dd243f333402f59fe28abdbbbae301e7b659c7a26d5c0f979",
|
||||
"06f94a2996158a819fe34c40de3cf0379fd9fb85b3e363ba3926a0e7d960e3f4c2e0c70c7ce0ccb2a64fc29869f6e7ab12bd4d3f14fce943279027e785fb5c29",
|
||||
"c29c399ef3eee8961e87565c1ce263925fc3d0ce267d13e48dd9e732ee67b0f69fad56401b0f10fcaac119201046cca28c5b14abdea3212ae65562f7f138db3d",
|
||||
"4cec4c9df52eef05c3f6faaa9791bc7445937183224ecc37a1e58d0132d35617531d7e795f52af7b1eb9d147de1292d345fe341823f8e6bc1e5badca5c656108",
|
||||
"898bfbae93b3e18d00697eab7d9704fa36ec339d076131cefdf30edbe8d9cc81c3a80b129659b163a323bab9793d4feed92d54dae966c77529764a09be88db45",
|
||||
"ee9bd0469d3aaf4f14035be48a2c3b84d9b4b1fff1d945e1f1c1d38980a951be197b25fe22c731f20aeacc930ba9c4a1f4762227617ad350fdabb4e80273a0f4",
|
||||
"3d4d3113300581cd96acbf091c3d0f3c310138cd6979e6026cde623e2dd1b24d4a8638bed1073344783ad0649cc6305ccec04beb49f31c633088a99b65130267",
|
||||
"95c0591ad91f921ac7be6d9ce37e0663ed8011c1cfd6d0162a5572e94368bac02024485e6a39854aa46fe38e97d6c6b1947cd272d86b06bb5b2f78b9b68d559d",
|
||||
"227b79ded368153bf46c0a3ca978bfdbef31f3024a5665842468490b0ff748ae04e7832ed4c9f49de9b1706709d623e5c8c15e3caecae8d5e433430ff72f20eb",
|
||||
"5d34f3952f0105eef88ae8b64c6ce95ebfade0e02c69b08762a8712d2e4911ad3f941fc4034dc9b2e479fdbcd279b902faf5d838bb2e0c6495d372b5b7029813",
|
||||
"7f939bf8353abce49e77f14f3750af20b7b03902e1a1e7fb6aaf76d0259cd401a83190f15640e74f3e6c5a90e839c7821f6474757f75c7bf9002084ddc7a62dc",
|
||||
"062b61a2f9a33a71d7d0a06119644c70b0716a504de7e5e1be49bd7b86e7ed6817714f9f0fc313d06129597e9a2235ec8521de36f7290a90ccfc1ffa6d0aee29",
|
||||
"f29e01eeae64311eb7f1c6422f946bf7bea36379523e7b2bbaba7d1d34a22d5ea5f1c5a09d5ce1fe682cced9a4798d1a05b46cd72dff5c1b355440b2a2d476bc",
|
||||
"ec38cd3bbab3ef35d7cb6d5c914298351d8a9dc97fcee051a8a02f58e3ed6184d0b7810a5615411ab1b95209c3c810114fdeb22452084e77f3f847c6dbaafe16",
|
||||
"c2aef5e0ca43e82641565b8cb943aa8ba53550caef793b6532fafad94b816082f0113a3ea2f63608ab40437ecc0f0229cb8fa224dcf1c478a67d9b64162b92d1",
|
||||
"15f534efff7105cd1c254d074e27d5898b89313b7d366dc2d7d87113fa7d53aae13f6dba487ad8103d5e854c91fdb6e1e74b2ef6d1431769c30767dde067a35c",
|
||||
"89acbca0b169897a0a2714c2df8c95b5b79cb69390142b7d6018bb3e3076b099b79a964152a9d912b1b86412b7e372e9cecad7f25d4cbab8a317be36492a67d7",
|
||||
"e3c0739190ed849c9c962fd9dbb55e207e624fcac1eb417691515499eea8d8267b7e8f1287a63633af5011fde8c4ddf55bfdf722edf88831414f2cfaed59cb9a",
|
||||
"8d6cf87c08380d2d1506eee46fd4222d21d8c04e585fbfd08269c98f702833a156326a0724656400ee09351d57b440175e2a5de93cc5f80db6daf83576cf75fa",
|
||||
"da24bede383666d563eeed37f6319baf20d5c75d1635a6ba5ef4cfa1ac95487e96f8c08af600aab87c986ebad49fc70a58b4890b9c876e091016daf49e1d322e",
|
||||
"f9d1d1b1e87ea7ae753a029750cc1cf3d0157d41805e245c5617bb934e732f0ae3180b78e05bfe76c7c3051e3e3ac78b9b50c05142657e1e03215d6ec7bfd0fc",
|
||||
"11b7bc1668032048aa43343de476395e814bbbc223678db951a1b03a021efac948cfbe215f97fe9a72a2f6bc039e3956bfa417c1a9f10d6d7ba5d3d32ff323e5",
|
||||
"b8d9000e4fc2b066edb91afee8e7eb0f24e3a201db8b6793c0608581e628ed0bcc4e5aa6787992a4bcc44e288093e63ee83abd0bc3ec6d0934a674a4da13838a",
|
||||
"ce325e294f9b6719d6b61278276ae06a2564c03bb0b783fafe785bdf89c7d5acd83e78756d301b445699024eaeb77b54d477336ec2a4f332f2b3f88765ddb0c3",
|
||||
"29acc30e9603ae2fccf90bf97e6cc463ebe28c1b2f9b4b765e70537c25c702a29dcbfbf14c99c54345ba2b51f17b77b5f15db92bbad8fa95c471f5d070a137cc",
|
||||
"3379cbaae562a87b4c0425550ffdd6bfe1203f0d666cc7ea095be407a5dfe61ee91441cd5154b3e53b4f5fb31ad4c7a9ad5c7af4ae679aa51a54003a54ca6b2d",
|
||||
"3095a349d245708c7cf550118703d7302c27b60af5d4e67fc978f8a4e60953c7a04f92fcf41aee64321ccb707a895851552b1e37b00bc5e6b72fa5bcef9e3fff",
|
||||
"07262d738b09321f4dbccec4bb26f48cb0f0ed246ce0b31b9a6e7bc683049f1f3e5545f28ce932dd985c5ab0f43bd6de0770560af329065ed2e49d34624c2cbb",
|
||||
"b6405eca8ee3316c87061cc6ec18dba53e6c250c63ba1f3bae9e55dd3498036af08cd272aa24d713c6020d77ab2f3919af1a32f307420618ab97e73953994fb4",
|
||||
"7ee682f63148ee45f6e5315da81e5c6e557c2c34641fc509c7a5701088c38a74756168e2cd8d351e88fd1a451f360a01f5b2580f9b5a2e8cfc138f3dd59a3ffc",
|
||||
"1d263c179d6b268f6fa016f3a4f29e943891125ed8593c81256059f5a7b44af2dcb2030d175c00e62ecaf7ee96682aa07ab20a611024a28532b1c25b86657902",
|
||||
"106d132cbdb4cd2597812846e2bc1bf732fec5f0a5f65dbb39ec4e6dc64ab2ce6d24630d0f15a805c3540025d84afa98e36703c3dbee713e72dde8465bc1be7e",
|
||||
"0e79968226650667a8d862ea8da4891af56a4e3a8b6d1750e394f0dea76d640d85077bcec2cc86886e506751b4f6a5838f7f0b5fef765d9dc90dcdcbaf079f08",
|
||||
"521156a82ab0c4e566e5844d5e31ad9aaf144bbd5a464fdca34dbd5717e8ff711d3ffebbfa085d67fe996a34f6d3e4e60b1396bf4b1610c263bdbb834d560816",
|
||||
"1aba88befc55bc25efbce02db8b9933e46f57661baeabeb21cc2574d2a518a3cba5dc5a38e49713440b25f9c744e75f6b85c9d8f4681f676160f6105357b8406",
|
||||
"5a9949fcb2c473cda968ac1b5d08566dc2d816d960f57e63b898fa701cf8ebd3f59b124d95bfbbedc5f1cf0e17d5eaed0c02c50b69d8a402cabcca4433b51fd4",
|
||||
"b0cead09807c672af2eb2b0f06dde46cf5370e15a4096b1a7d7cbb36ec31c205fbefca00b7a4162fa89fb4fb3eb78d79770c23f44e7206664ce3cd931c291e5d",
|
||||
"bb6664931ec97044e45b2ae420ae1c551a8874bc937d08e969399c3964ebdba8346cdd5d09caafe4c28ba7ec788191ceca65ddd6f95f18583e040d0f30d0364d",
|
||||
"65bc770a5faa3792369803683e844b0be7ee96f29f6d6a35568006bd5590f9a4ef639b7a8061c7b0424b66b60ac34af3119905f33a9d8c3ae18382ca9b689900",
|
||||
"ea9b4dca333336aaf839a45c6eaa48b8cb4c7ddabffea4f643d6357ea6628a480a5b45f2b052c1b07d1fedca918b6f1139d80f74c24510dcbaa4be70eacc1b06",
|
||||
"e6342fb4a780ad975d0e24bce149989b91d360557e87994f6b457b895575cc02d0c15bad3ce7577f4c63927ff13f3e381ff7e72bdbe745324844a9d27e3f1c01",
|
||||
"3e209c9b33e8e461178ab46b1c64b49a07fb745f1c8bc95fbfb94c6b87c69516651b264ef980937fad41238b91ddc011a5dd777c7efd4494b4b6ecd3a9c22ac0",
|
||||
"fd6a3d5b1875d80486d6e69694a56dbb04a99a4d051f15db2689776ba1c4882e6d462a603b7015dc9f4b7450f05394303b8652cfb404a266962c41bae6e18a94",
|
||||
"951e27517e6bad9e4195fc8671dee3e7e9be69cee1422cb9fecfce0dba875f7b310b93ee3a3d558f941f635f668ff832d2c1d033c5e2f0997e4c66f147344e02",
|
||||
"8eba2f874f1ae84041903c7c4253c82292530fc8509550bfdc34c95c7e2889d5650b0ad8cb988e5c4894cb87fbfbb19612ea93ccc4c5cad17158b9763464b492",
|
||||
"16f712eaa1b7c6354719a8e7dbdfaf55e4063a4d277d947550019b38dfb564830911057d50506136e2394c3b28945cc964967d54e3000c2181626cfb9b73efd2",
|
||||
"c39639e7d5c7fb8cdd0fd3e6a52096039437122f21c78f1679cea9d78a734c56ecbeb28654b4f18e342c331f6f7229ec4b4bc281b2d80a6eb50043f31796c88c",
|
||||
"72d081af99f8a173dcc9a0ac4eb3557405639a29084b54a40172912a2f8a395129d5536f0918e902f9e8fa6000995f4168ddc5f893011be6a0dbc9b8a1a3f5bb",
|
||||
"c11aa81e5efd24d5fc27ee586cfd8847fbb0e27601ccece5ecca0198e3c7765393bb74457c7e7a27eb9170350e1fb53857177506be3e762cc0f14d8c3afe9077",
|
||||
"c28f2150b452e6c0c424bcde6f8d72007f9310fed7f2f87de0dbb64f4479d6c1441ba66f44b2accee61609177ed340128b407ecec7c64bbe50d63d22d8627727",
|
||||
"f63d88122877ec30b8c8b00d22e89000a966426112bd44166e2f525b769ccbe9b286d437a0129130dde1a86c43e04bedb594e671d98283afe64ce331de9828fd",
|
||||
"348b0532880b88a6614a8d7408c3f913357fbb60e995c60205be9139e74998aede7f4581e42f6b52698f7fa1219708c14498067fd1e09502de83a77dd281150c",
|
||||
"5133dc8bef725359dff59792d85eaf75b7e1dcd1978b01c35b1b85fcebc63388ad99a17b6346a217dc1a9622ebd122ecf6913c4d31a6b52a695b86af00d741a0",
|
||||
"2753c4c0e98ecad806e88780ec27fccd0f5c1ab547f9e4bf1659d192c23aa2cc971b58b6802580baef8adc3b776ef7086b2545c2987f348ee3719cdef258c403",
|
||||
"b1663573ce4b9d8caefc865012f3e39714b9898a5da6ce17c25a6a47931a9ddb9bbe98adaa553beed436e89578455416c2a52a525cf2862b8d1d49a2531b7391",
|
||||
"64f58bd6bfc856f5e873b2a2956ea0eda0d6db0da39c8c7fc67c9f9feefcff3072cdf9e6ea37f69a44f0c61aa0da3693c2db5b54960c0281a088151db42b11e8",
|
||||
"0764c7be28125d9065c4b98a69d60aede703547c66a12e17e1c618994132f5ef82482c1e3fe3146cc65376cc109f0138ed9a80e49f1f3c7d610d2f2432f20605",
|
||||
"f748784398a2ff03ebeb07e155e66116a839741a336e32da71ec696001f0ad1b25cd48c69cfca7265eca1dd71904a0ce748ac4124f3571076dfa7116a9cf00e9",
|
||||
"3f0dbc0186bceb6b785ba78d2a2a013c910be157bdaffae81bb6663b1a73722f7f1228795f3ecada87cf6ef0078474af73f31eca0cc200ed975b6893f761cb6d",
|
||||
"d4762cd4599876ca75b2b8fe249944dbd27ace741fdab93616cbc6e425460feb51d4e7adcc38180e7fc47c89024a7f56191adb878dfde4ead62223f5a2610efe",
|
||||
"cd36b3d5b4c91b90fcbba79513cfee1907d8645a162afd0cd4cf4192d4a5f4c892183a8eacdb2b6b6a9d9aa8c11ac1b261b380dbee24ca468f1bfd043c58eefe",
|
||||
"98593452281661a53c48a9d8cd790826c1a1ce567738053d0bee4a91a3d5bd92eefdbabebe3204f2031ca5f781bda99ef5d8ae56e5b04a9e1ecd21b0eb05d3e1",
|
||||
"771f57dd2775ccdab55921d3e8e30ccf484d61fe1c1b9c2ae819d0fb2a12fab9be70c4a7a138da84e8280435daade5bbe66af0836a154f817fb17f3397e725a3",
|
||||
"c60897c6f828e21f16fbb5f15b323f87b6c8955eabf1d38061f707f608abdd993fac3070633e286cf8339ce295dd352df4b4b40b2f29da1dd50b3a05d079e6bb",
|
||||
"8210cd2c2d3b135c2cf07fa0d1433cd771f325d075c6469d9c7f1ba0943cd4ab09808cabf4acb9ce5bb88b498929b4b847f681ad2c490d042db2aec94214b06b",
|
||||
"1d4edfffd8fd80f7e4107840fa3aa31e32598491e4af7013c197a65b7f36dd3ac4b478456111cd4309d9243510782fa31b7c4c95fa951520d020eb7e5c36e4ef",
|
||||
"af8e6e91fab46ce4873e1a50a8ef448cc29121f7f74deef34a71ef89cc00d9274bc6c2454bbb3230d8b2ec94c62b1dec85f3593bfa30ea6f7a44d7c09465a253",
|
||||
"29fd384ed4906f2d13aa9fe7af905990938bed807f1832454a372ab412eea1f5625a1fcc9ac8343b7c67c5aba6e0b1cc4644654913692c6b39eb9187ceacd3ec",
|
||||
"a268c7885d9874a51c44dffed8ea53e94f78456e0b2ed99ff5a3924760813826d960a15edbedbb5de5226ba4b074e71b05c55b9756bb79e55c02754c2c7b6c8a",
|
||||
"0cf8545488d56a86817cd7ecb10f7116b7ea530a45b6ea497b6c72c997e09e3d0da8698f46bb006fc977c2cd3d1177463ac9057fdd1662c85d0c126443c10473",
|
||||
"b39614268fdd8781515e2cfebf89b4d5402bab10c226e6344e6b9ae000fb0d6c79cb2f3ec80e80eaeb1980d2f8698916bd2e9f747236655116649cd3ca23a837",
|
||||
"74bef092fc6f1e5dba3663a3fb003b2a5ba257496536d99f62b9d73f8f9eb3ce9ff3eec709eb883655ec9eb896b9128f2afc89cf7d1ab58a72f4a3bf034d2b4a",
|
||||
"3a988d38d75611f3ef38b8774980b33e573b6c57bee0469ba5eed9b44f29945e7347967fba2c162e1c3be7f310f2f75ee2381e7bfd6b3f0baea8d95dfb1dafb1",
|
||||
"58aedfce6f67ddc85a28c992f1c0bd0969f041e66f1ee88020a125cbfcfebcd61709c9c4eba192c15e69f020d462486019fa8dea0cd7a42921a19d2fe546d43d",
|
||||
"9347bd291473e6b4e368437b8e561e065f649a6d8ada479ad09b1999a8f26b91cf6120fd3bfe014e83f23acfa4c0ad7b3712b2c3c0733270663112ccd9285cd9",
|
||||
"b32163e7c5dbb5f51fdc11d2eac875efbbcb7e7699090a7e7ff8a8d50795af5d74d9ff98543ef8cdf89ac13d0485278756e0ef00c817745661e1d59fe38e7537",
|
||||
"1085d78307b1c4b008c57a2e7e5b234658a0a82e4ff1e4aaac72b312fda0fe27d233bc5b10e9cc17fdc7697b540c7d95eb215a19a1a0e20e1abfa126efd568c7",
|
||||
"4e5c734c7dde011d83eac2b7347b373594f92d7091b9ca34cb9c6f39bdf5a8d2f134379e16d822f6522170ccf2ddd55c84b9e6c64fc927ac4cf8dfb2a17701f2",
|
||||
"695d83bd990a1117b3d0ce06cc888027d12a054c2677fd82f0d4fbfc93575523e7991a5e35a3752e9b70ce62992e268a877744cdd435f5f130869c9a2074b338",
|
||||
"a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15",
|
||||
"d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9",
|
||||
"142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461",
|
||||
}
|
||||
|
||||
var hashes2X = []string{
|
||||
"64",
|
||||
"f457",
|
||||
"e8c045",
|
||||
"a74c6d0d",
|
||||
"eb02ae482a",
|
||||
"be65b981275e",
|
||||
"8540ccd083a455",
|
||||
"074a02fa58d7c7c0",
|
||||
"da6da05e10db3022b6",
|
||||
"542a5aae2f28f2c3b68c",
|
||||
"ca3af2afc4afe891da78b1",
|
||||
"e0f66b8dcebf4edc85f12c85",
|
||||
"744224d383733b3fa2c53bfcf5",
|
||||
"b09b653e85b72ef5cdf8fcfa95f3",
|
||||
"dd51877f31f1cf7b9f68bbb09064a3",
|
||||
"f5ebf68e7ebed6ad445ffc0c47e82650",
|
||||
"ebdcfe03bcb7e21a9091202c5938c0a1bb",
|
||||
"860fa5a72ff92efafc48a89df1632a4e2809",
|
||||
"0d6d49daa26ae2818041108df3ce0a4db48c8d",
|
||||
"e5d7e1bc5715f5ae991e4043e39533af5d53e47f",
|
||||
"5232028a43b9d4dfa7f37439b49495926481ab8a29",
|
||||
"c118803c922f9ae2397fb676a2ab7603dd9c29c21fe4",
|
||||
"2af924f48b9bd7076bfd68794bba6402e2a7ae048de3ea",
|
||||
"61255ac38231087c79ea1a0fa14538c26be1c851b6f318c0",
|
||||
"f9712b8e42f0532162822f142cb946c40369f2f0e77b6b186e",
|
||||
"76da0b89558df66f9b1e66a61d1e795b178ce77a359087793ff2",
|
||||
"9036fd1eb32061bdecebc4a32aa524b343b8098a16768ee774d93c",
|
||||
"f4ce5a05934e125d159678bea521f585574bcf9572629f155f63efcc",
|
||||
"5e1c0d9fae56393445d3024d6b82692d1339f7b5936f68b062c691d3bf",
|
||||
"538e35f3e11111d7c4bab69f83b30ade4f67addf1f45cdd2ac74bf299509",
|
||||
"17572c4dcbb17faf8785f3bba9f6903895394352eae79b01ebd758377694cc",
|
||||
"29f6bb55de7f8868e053176c878c9fe6c2055c4c5413b51ab0386c277fdbac75",
|
||||
"bad026c8b2bd3d294907f2280a7145253ec2117d76e3800357be6d431b16366e41",
|
||||
"386b7cb6e0fd4b27783125cbe80065af8eb9981fafc3ed18d8120863d972fa7427d9",
|
||||
"06e8e6e26e756fff0b83b226dce974c21f970e44fb5b3e5bbada6e4b12f81cca666f48",
|
||||
"2f9bd300244f5bc093ba6dcdb4a89fa29da22b1de9d2c9762af919b5fedf6998fbda305b",
|
||||
"cf6bdcc46d788074511f9e8f0a4b86704365b2d3f98340b8db53920c385b959a38c8869ae7",
|
||||
"1171e603e5cdeb4cda8fd7890222dd8390ede87b6f3284cac0f0d832d8250c9200715af7913d",
|
||||
"bda7b2ad5d02bd35ffb009bdd72b7d7bc9c28b3a32f32b0ba31d6cbd3ee87c60b7b98c03404621",
|
||||
"2001455324e748503aa08eff2fb2e52ae0170e81a6e9368ada054a36ca340fb779393fb045ac72b3",
|
||||
"45f0761aefafbf87a68f9f1f801148d9bba52616ad5ee8e8ac9207e9846a782f487d5cca8b20355a18",
|
||||
"3a7e05708be62f087f17b41ac9f20e4ef8115c5ab6d08e84d46af8c273fb46d3ce1aabebae5eea14e018",
|
||||
"ea318da9d042ca337ccdfb2bee3e96ecb8f907876c8d143e8e44569178353c2e593e4a82c265931ba1dd79",
|
||||
"e0f7c08f5bd712f87094b04528fadb283d83c9ceb82a3e39ec31c19a42a1a1c3bee5613b5640abe069b0d690",
|
||||
"d35e63fb1f3f52ab8f7c6cd7c8247e9799042e53922fbaea808ab979fa0c096588cfea3009181d2f93002dfc11",
|
||||
"b8b0ab69e3ae55a8699eb481dd665b6a2424c89bc6b7cca02d15fdf1b9854139cab49d34de498b50b2c7e8b910cf",
|
||||
"fb65e3222a2950eae1701d4cdd4736266f65bf2c0d2e77968996eadb60ef74fb786f6234973a2524bdfe32d100aa0e",
|
||||
"f28b4bb3a2e2c4d5c01a23ff134558559a2d3d704b75402983ee4e0f71d273ae056842c4153b18ee5c47e2bfa54313d4",
|
||||
"7bb78794e58a53c3e4b1aeb161e756af051583d14e0a5a3205e094b7c9a8cf62d098fa9ea1db12f330a51ab9852c17f983",
|
||||
"a879a8ebae4d0987789bcc58ec3448e35ba1fa1ee58c668d8295aba4eaeaf2762b053a677e25404f635a53037996974d418a",
|
||||
"695865b353ec701ecc1cb38f3154489eed0d39829fc192bb68db286d20fa0a64235cde5639137819f7e99f86bd89afcef84a0f",
|
||||
"a6ec25f369f71176952fb9b33305dc768589a6070463ee4c35996e1ced4964a865a5c3dc8f0d809eab71366450de702318e4834d",
|
||||
"604749f7bfadb069a036409ffac5ba291fa05be8cba2f141554132f56d9bcb88d1ce12f2004cd3ade1aa66a26e6ef64e327514096d",
|
||||
"daf9fa7dc2464a899533594e7916fc9bc585bd29dd60c930f3bfa78bc47f6c8439448043a45119fc9228c15bce5fd24f46baf9de736b",
|
||||
"943ea5647a8666763084da6a6f15dcf0e8dc24f27fd0d9194805d25180fe3a6d98f4b2b5e0d6a04e9b41869817030f16ae975dd41fc35c",
|
||||
"af4f73cbfc093760dfeb52d57ef45207bbd1a515f5523404e5d95a73c237d97ae65bd195b472de6d514c2c448b12fafc282166da132258e9",
|
||||
"605f4ed72ed7f5046a342fe4cf6808100d4632e610d59f7ebb016e367d0ff0a95cf45b02c727ba71f147e95212f52046804d376c918cadd260",
|
||||
"3750d8ab0a6b13f78e51d321dfd1aa801680e958de45b7b977d05732ee39f856b27cb2bcce8fbf3db6666d35e21244c2881fdcc27fbfea6b1672",
|
||||
"8f1b929e80ab752b58abe9731b7b34eb61369536995abef1c0980d93903c1880da3637d367456895f0cb4769d6de3a979e38ed6f5f6ac4d48e9b32",
|
||||
"d8469b7aa538b36cdc711a591d60dafecca22bd421973a70e2deef72f69d8014a6f0064eabfbebf5383cbb90f452c6e113d2110e4b1092c54a38b857",
|
||||
"7d1f1ad2029f4880e1898af8289c23bc933a40863cc4ab697fead79c58b6b8e25b68cf5324579b0fe879fe7a12e6d03907f0140dfe7b29d33d6109ecf1",
|
||||
"87a77aca6d551642288a0dff66078225ae39d288801607429d6725ca949eed7a6f199dd8a65523b4ee7cfa4187400e96597bfffc3e38ade0ae0ab88536a9",
|
||||
"e101f43179d8e8546e5ce6a96d7556b7e6b9d4a7d00e7aade5579d085d527ce34a9329551ebcaf6ba946949bbe38e30a62ae344c1950b4bde55306b3bac432",
|
||||
"4324561d76c370ef35ac36a4adf8f3773a50d86504bd284f71f7ce9e2bc4c1f1d34a7fb2d67561d101955d448b67577eb30dfee96a95c7f921ef53e20be8bc44",
|
||||
"78f0ed6e220b3da3cc9381563b2f72c8dc830cb0f39a48c6ae479a6a78dcfa94002631dec467e9e9b47cc8f0887eb680e340aec3ec009d4a33d241533c76c8ca8c",
|
||||
"9f6589c31a472e0a736f4eb22b6c70a9d332cc15304ccb66a6b97cd051b6ed82f8990e1d9bee2e4bb1c3c45e550ae0e7b96e93ae23f2fb8f63b309131e72b36cba6a",
|
||||
"c138077ee4ed3d7ffa85ba851dfdf6e9843fc1dc00889d117237bfaad9aa757192f73556b959f98e6d24886ce48869f2a01a48c371785f12b6484eb2078f08c22066e1",
|
||||
"f83e7c9e0954a500576ea1fc90a3db2cbd7994eaef647dab5b34e88ab9dc0b47addbc807b21c8e6dd3d0bd357f008471d4f3e0abb18450e1d4919e03a34545b9643f870e",
|
||||
"3277a11f2628544fc66f50428f1ad56bcba6ee36ba2ca6ecdf7e255effc0c30235c039d13e01f04cf1efe95b5c2033ab72adda30994b62f2851d17c9920eadca9a251752dc",
|
||||
"c2a834281a06fe7b730d3a03f90761daf02714c066e33fc07e1f59ac801ec2f4433486b5a2da8faa51a0cf3c34e29b2960cd0013378938dbd47c3a3d12d70db01d7d06c3e91e",
|
||||
"47680182924a51cabe142a6175c9253e8ba7ea579ece8d9bcb78b1e9ca00db844fa08abcf41702bd758ee2c608d9612fed50e85854469cb4ef3038acf1e35b6ba4390561d8ae82",
|
||||
"cec45830cd71869e83b109a99a3cd7d935f83a95de7c582f3adbd34e4938fa2f3f922f52f14f169c38cc6618d3f306a8a4d607b345b8a9c48017136fbf825aecf7b620e85f837fae",
|
||||
"46fb53c70ab105079d5d78dc60eaa30d938f26e4d0b9df122e21ec85deda94744c1daf8038b8a6652d1ff3e7e15376f5abd30e564784a999f665078340d66b0e939e0c2ef03f9c08bb",
|
||||
"7b0dcb52791a170cc52f2e8b95d8956f325c3751d3ef3b2b83b41d82d4496b46228a750d02b71a96012e56b0720949ca77dc68be9b1ef1ad6d6a5ceb86bf565cb972279039e209dddcdc",
|
||||
"7153fd43e6b05f5e1a4401e0fef954a737ed142ec2f60bc4daeef9ce73ea1b40a0fcaf1a1e03a3513f930dd5335723632f59f7297fe3a98b68e125eadf478eb045ed9fc4ee566d13f537f5",
|
||||
"c7f569c79c801dab50e9d9ca6542f25774b3841e49c83efe0b89109f569509ce7887bc0d2b57b50320eb81fab9017f16c4c870e59edb6c26620d93748500231d70a36f48a7c60747ca2d5986",
|
||||
"0a81e0c547648595adca65623ce783411aac7f7d30c3ad269efafab288e7186f6895261972f5137877669c550f34f5128850ebb50e1884814ea1055ee29a866afd04b2087abed02d9592573428",
|
||||
"6a7b6769e1f1c95314b0c7fe77013567891bd23416374f23e4f43e27bc4c55cfada13b53b1581948e07fb96a50676baa2756db0988077b0f27d36ac088e0ff0fe72eda1e8eb4b8facff3218d9af0",
|
||||
"a399474595cb1ccab6107f18e80f03b1707745c7bf769fc9f260094dc9f8bc6fe09271cb0b131ebb2acd073de4a6521c8368e664278be86be216d1622393f23435fae4fbc6a2e7c961282a777c2d75",
|
||||
"4f0fc590b2755a515ae6b46e9628092369d9c8e589e3239320639aa8f7aa44f8111c7c4b3fdbe6e55e036fbf5ebc9c0aa87a4e66851c11e86f6cbf0bd9eb1c98a378c7a7d3af900f55ee108b59bc9e5c",
|
||||
"ed96a046f08dd675107331d267379c6fce3c352a9f8d7b243008a74cb4e9410836afaabe871dab6038ca94ce5f6d41fa922ce08aba58169f94cfc86d9f688f396abd24c11a6a9b0830572105a477c33e92",
|
||||
"379955f539abf0eb2972ee99ed9546c4bbee363403991833005dc27904c271ef22a799bc32cb39f08d2e4ba6717d55153feb692d7c5efae70890bf29d96df02333c7b05ccc314e4835b018fec9141a82c745",
|
||||
"e16cc8d41b96547ede0d0cf4d908c5fa393399daa4a9696e76a4c1f6a2a9fef70f17fb53551a8145ed88f18db8fe780a079d94732437023f7c1d1849ef69ad536a76204239e8ba5d97e507c36c7d042f87fe0e",
|
||||
"a81de50750ece3f84536728f227208bf01ec5b7721579d007de72c88ee20663318332efe5bc7c09ad1fa8342be51f0609046ccf760a7957a7d8dc88941adb93666a4521ebe76618e5ddc2dd3261493d400b50073",
|
||||
"b72c5fb7c7f60d243928fa41a2d711157b96aef290185c64b4de3dcfa3d644da67a8f37c2ac55caad79ec695a473e8b481f658c497edb8a191526592b11a412282d2a4010c90ef4647bd6ce745ebc9244a71d4876b",
|
||||
"9550703877079c90e200e830f277b605624954c549e729c359ee01ee2b07741ecc4255cb37f96682dafcdbaade1063e2c5ccbd1918fb669926a67744101fb6de3ac016be4c74165a1e5a696b704ba2ebf4a953d44b95",
|
||||
"a17eb44d4de502dc04a80d5a5e9507d17f27c96467f24c79b06bc98a4c410741d4ac2db98ec02c2a976d788531f1a4451b6c6204cef6dae1b6ebbcd0bde23e6fffb02754043c8fd3c783d90a670b16879ce68b5554fe1c",
|
||||
"41d3ea1eaba5be4a206732dbb5b70b79b66a6e5908795ad4fb7cf9e67efb13f06fef8f90acb080ce082aadec6a1b543af759ab63fa6f1d3941186482b0c2b312f1151ea8386253a13ed3708093279b8eb04185636488b226",
|
||||
"5e7cdd8373dc42a243c96013cd29df9283b5f28bb50453a903c85e2ce57f35861bf93f03029072b70dac0804e7d51fd0c578c8d9fa619f1e9ce3d8044f65d55634dba611280c1d5cfb59c836a595c803124f696b07ddfac718",
|
||||
"26a14c4aa168907cb5de0d12a82e1373a128fb21f2ed11feba108b1bebce934ad63ed89f4ed7ea5e0bc8846e4fc10142f82de0bebd39d68f7874f615c3a9c896bab34190e85df05aaa316e14820b5e478d838fa89dfc94a7fc1e",
|
||||
"0211dfc3c35881adc170e4ba6daab1b702dff88933db9a6829a76b8f4a7c2a6d658117132a974f0a0b3a38ceea1efc2488da21905345909e1d859921dc2b5054f09bce8eeb91fa2fc6d048ce00b9cd655e6aafbdaa3a2f19270a16",
|
||||
"ddf015b01b68c4f5f72c3145d54049867d99ee6bef24282abf0eecdb506e295bacf8f23ffa65a4cd891f76a046b9dd82cae43a8d01e18a8dff3b50aeb92672be69d7c087ec1fa2d3b2a39196ea5b49b7baede37a586fea71aded587f",
|
||||
"6ee721f71ca4dd5c9ce7873c5c04c6ce76a2c824b984251c15535afc96adc9a4d48ca314bfeb6b8ee65092f14cf2a7ca9614e1dcf24c2a7f0f0c11207d3d8aed4af92873b56e8b9ba2fbd659c3f4ca90fa24f113f74a37181bf0fdf758",
|
||||
"689bd150e65ac123612524f720f54def78c095eaab8a87b8bcc72b443408e3227f5c8e2bd5af9bcac684d497bc3e41b7a022c28fb5458b95e8dfa2e8caccde0492936ff1902476bb7b4ef2125b19aca2cd3384d922d9f36dddbcd96ae0d6",
|
||||
"3a3c0ef066fa4390ec76ad6be1dc9c31ddf45fef43fbfa1f49b439caa2eb9f3042253a9853e96a9cf86b4f873785a5d2c5d3b05f6501bc876e09031188e05f48937bf3c9b667d14800db62437590b84ce96aa70bb5141ee2ea41b55a6fd944",
|
||||
"741ce384e5e0edaebb136701ce38b3d33215415197758ae81235307a4115777d4dab23891db530c6d28f63a957428391421f742789a0e04c99c828373d9903b64dd57f26b3a38b67df829ae243feef731ead0abfca049924667fdec49d40f665",
|
||||
"a513f450d66cd5a48a115aee862c65b26e836f35a5eb6894a80519e2cd96cc4cad8ed7eb922b4fc9bbc55c973089d627b1da9c3a95f6c019ef1d47143cc545b15e4244424be28199c51a5efc7234dcd94e72d229897c392af85f523c2633427825",
|
||||
"71f1554d2d49bb7bd9e62e71fa049fb54a2c097032f61ebda669b3e1d4593962e47fc62a0ab5d85706aebd6a2f9a192c88aa1ee2f6a46710cf4af6d3c25b7e68ad5c3db23ac009c8f13625ff85dc8e50a9a1b2682d3329330b973ec8cbb7bb73b2bd",
|
||||
"167cc1067bc08a8d2c1a0c10041ebe1fc327b37043f6bd8f1c63569e9d36ded58519e66b162f34b6d8f1107ef1e3de199d97b36b44141a1fc4f49b883f40507ff11f909a017869dc8a2357fc7336ae68703d25f75710b0ff5f9765321c0fa53a51675c",
|
||||
"cb859b35dc70e264efaad2a809fea1e71cd4a3f924be3b5a13f8687a1166b538c40b2ad51d5c3e47b0de482497382673140f547068ff0b3b0fb7501209e1bf36082509ae85f60bb98fd02ac50d883a1a8daa704952d83c1f6da60c9624bc7c99912930bf",
|
||||
"afb1f0c6b7125b04fa2578dd40f60cb411b35ebc7026c702e25b3f0ae3d4695d44cfdf37cb755691dd9c365edadf21ee44245620e6a24d4c2497135b37cd7ac67e3bd0aaee9f63f107746f9b88859ea902bc7d6895406aa2161f480cad56327d0a5bba2836",
|
||||
"13e9c0522587460d90c7cb354604de8f1bf850e75b4b176bda92862d35ec810861f7d5e7ff6ba9302f2c2c8642ff8b7776a2f53665790f570fcef3cac069a90d50db42227331c4affb33d6c040d75b9aeafc9086eb83ced38bb02c759e95ba08c92b17031288",
|
||||
"0549812d62d3ed497307673a4806a21060987a4dbbf43d352b9b170a29240954cf04bc3e1e250476e6800b79e843a8bd8253b7d743de01ab336e978d4bea384eaff700ce020691647411b10a60acacb6f8837fb08ad666b8dcc9eaa87ccb42aef6914a3f3bc30a",
|
||||
"3a263efbe1f2d463f20526e1d0fd735035fd3f808925f058b32c4d8788aeeab9b8ce233b3c34894731cd73361f465bd350395aebcabd2fb63010298ca025d849c1fa3cd573309b74d7f824bbfe383f09db24bcc565f636b877333206a6ad70815c3bef5574c5fc1c",
|
||||
"3c6a7d8a84ef7e3eaa812fc1eb8e85105467230d2c9e4562edbfd808f4d1ac15d16b786cc6a02959c2bc17149c2ce74c6f85ee5ef22a8a96b9be1f197cffd214c1ab02a06a9227f37cd432579f8c28ff2b5ac91cca8ffe6240932739d56788c354e92c591e1dd76499",
|
||||
"b571859294b02af17541a0b5e899a5f67d6f5e36d38255bc417486e69240db56b09cf2607fbf4f95d085a779358a8a8b41f36503438c1860c8f361ce0f2783a08b21bd7232b50ca6d35428335272a5c05b436b2631d8d5c84d60e8040083768ce56a250727fb0579dd5c",
|
||||
"98ee1b7269d2a0dd490ca38d447279870ea55326571a1b430adbb2cf65c492131136f504145df3ab113a13abfb72c33663266b8bc9c458db4bf5d7ef03e1d3b8a99d5de0c024be8fabc8dc4f5dac82a0342d8ed65c329e7018d6997e69e29a01350516c86beaf153da65ac",
|
||||
"41c5c95f088df320d35269e5bf86d10248f17aec6776f0fe653f1c356aae409788c938befeb67c86d1c8870e8099ca0ce61a80fbb5a6654c44529368f70fc9b9c2f912f5092047d0ffc339577d24142300e34948e086f62e23ecaca410d24f8a36b5c8c5a80e0926bc8aa16a",
|
||||
"9f93c41f533b2a82a4df893c78faaaa793c1506974ba2a604cd33101713ca4adfd30819ffd8403402b8d40aff78106f3357f3e2c24312c0d3603a17184d7b999fc9908d14d50192aebabd90d05073da7af4be37dd3d81c90acc80e8333df546f17ab6874f1ec204392d1c0571e",
|
||||
"3da5207245ac270a915fc91cdb314e5a2577c4f8e269c4e701f0d7493ba716de79935918b917a2bd5db98050dbd1eb3894b65fac5abf13e075abebc011e651c03cafb6127147771a5c8418223e1548137a89206635c26ca9c235ccc108dc25cf846e4732444bd0c2782b197b262b",
|
||||
"96011af3965bb941dc8f749932ea484eccb9ba94e34b39f24c1e80410f96ce1d4f6e0aa5be606def4f54301e930493d4b55d484d93ab9dd4dc2c9cfb79345363af31ad42f4bd1aa6c77b8afc9f0d551bef7570b13b927afe3e7ac4de7603a0876d5edb1ad9be05e9ee8b53941e8f59",
|
||||
"51dbbf2a7ca224e524e3454fe82ddc901fafd2120fa8603bc343f129484e9600f688586e040566de0351d1693829045232d04ff31aa6b80125c763faab2a9b233313d931903dcfaba490538b06e4688a35886dc24cdd32a13875e6acf45454a8eb8a315ab95e608ad8b6a49aef0e299a",
|
||||
"5a6a422529e22104681e8b18d64bc0463a45df19ae2633751c7aae412c250f8fb2cd5e1270d3d0cf009c8aa69688ccd4e2b6536f5747a5bc479b20c135bf4e89d33a26118705a614c6be7ecfe766932471ad4ba01c4f045b1abb5070f90ec78439a27a1788db9327d1c32f939e5fb1d5ba",
|
||||
"5d26c983642093cb12ff0afabd87b7c56e211d01844ad6da3f623b9f20a0c968034299f2a65e6673530c5980a532beb831c7d0697d12760445986681076dfb6fae5f3a4d8f17a0db5008ce8619f566d2cfe4cf2a6d6f9c3664e3a48564a351c0b3c945c5ee24587521e4112c57e318be1b6a",
|
||||
"52641dbc6e36be4d905d8d60311e303e8e859cc47901ce30d6f67f152343e3c4030e3a33463793c19effd81fb7c4d631a9479a7505a983a052b1e948ce093b30efa595fab3a00f4cef9a2f664ceeb07ec61719212d58966bca9f00a7d7a8cb4024cf6476bab7fbccee5fd4e7c3f5e2b2975aa2",
|
||||
"a34ce135b37bf3db1c4aaa4878b4499bd2ee17b85578fcaf605d41e1826b45fdaa1b083d8235dc642787f11469a5493e36806504fe2a2063905e821475e2d5ee217057950370492f5024995e77b82aa51b4f5bd8ea24dc71e0a8a640b0592c0d80c24a726169cf0a10b40944747113d03b52708c",
|
||||
"46b3cdf4946e15a5334fc3244d6680f5fc132afa67bf43bfade23d0c9e0ec64e7dab76faaeca1870c05f96b7d019411d8b0873d9fed04fa5057c039d5949a4d592827f619471359d6171691cfa8a5d7cb07ef2804f6ccad4821c56d4988bea7765f660f09ef87405f0a80bcf8559efa111f2a0b419",
|
||||
"8b9fc21691477f11252fca050b121c5334eb4280aa11659e267297de1fec2b2294c7ccee9b59a149b9930b08bd320d3943130930a7d931b71d2f10234f4480c67f1de883d9894ada5ed5071660e221d78ae402f1f05af47761e13fec979f2671e3c63fb0ae7aa1327cf9b8313adab90794a52686bbc4",
|
||||
"cd6598924ce847de7ff45b20ac940aa6292a8a99b56a74eddc24f2cfb45797188614a21d4e8867e23ff75afd7cd324248d58fcf1ddc73fbd115dfa8c09e62022fab540a59f87c989c12a86ded05130939f00cd2f3b512963dfe0289f0e54acad881c1027d2a0292138fdee902d67d9669c0ca1034a9456",
|
||||
"594e1cd7337248704e691854af0fdb021067ddf7832b049ba7b684438c32b029eded2df2c89a6ff5f2f2c311522ae2dc6db5a815afc60637b15ec24ef9541f1550409db2a006da3affffe548a1eaee7bd114e9b805d0756c8e90c4dc33cb05226bc2b393b18d953f8730d4c7ae693159cdba758ad28964e2",
|
||||
"1f0d292453f04406ada8be4c161b82e3cdd69099a8637659e0ee40b8f6da46005cfc6085db9804852decfbe9f7b4dda019a7112612895a144ed430a960c8b2f5458d3d56b7f427cee6358915aee7146278aed2a0296cdd929e4d21ef95a3adf8b7a6beba673cdccdbdcfb2474711732d972ad054b2dc64f38d",
|
||||
"b65a72d4e1f9f9f75911cc46ad0806b9b18c87d105332a3fe183f45f063a746c892dc6c4b9181b1485b3e3a2cc3b453eba2d4c39d6905a774ed3fb755468beb190925ecd8e57ecb0d985125741650c6b6a1b2a3a50e93e3892c21d47ed5884eed83aa94e1602288f2f49fe286624de9d01fcb54433a0dc4ad70b",
|
||||
"705ce0ffa469250782aff725248fc88fe98eb76659e8407edc1c4842c9867d61fe64fb86f74e980598b92bc213d06f337bd5654fc28643c7ba769a4c31563427543c00808b627a19c90d86c322f33566ce020121cc322229c3337943d46f68ef939d613dcef0077269f88151d6398b6b009abb763410b154ad76a3",
|
||||
"7fa881ce87498440ab6af13854f0d851a7e0404de33896999a9b3292a5d2f5b3ad033530c558168fe5d2fdb9b89a2354c46cf32a0e612afc6c6485d789511bfef26800c74bf1a4cfbe30bda310d5f6029c3dccdedb6149e4971274e276dccfabd63bc4b9955e8303feb57f8a688db55ecb4b33d1f9fe1b3a8ba7ac32",
|
||||
"23a98f71c01c0408ae16843dc03be7db0aeaf055f951709d4e0dfdf64fffbffaf900ee592ee10929648e56f6c1e9f5be5793f7df66453eb56502c7c56c0f0c88da77abc8fa371e434104627ef7c663c49f40998dbad63fa6c7aa4fac17ae138d8bbe081f9bd168cd33c1fbc92fa35ed687679f48a64b87db1fe5bae675",
|
||||
"7b8970b6a33237e5a7bcb39272703edb92285c55842b30b9a48834b1b507cc02a6764739f2f7ee6ae02a7b715a1c455e59e8c77a1ae98abb10161853f1234d20da99016588cd8602d6b7ec7e177d4011edfa61e6b3766a3c6f8d6e9eac893c568903eb6e6aba9c4725774f6b4343b7acaa6c031593a36eef6c72806ff309",
|
||||
"f7f4d328ba108b7b1de4443e889a985ed52f485f3ca4e0c246aa5526590cbed344e9f4fe53e4eea0e761c82324649206ca8c2b45152157d4115e68c818644b03b65bb47ad79f94d37cb03c1d953b74c2b8adfa0e1c418bda9c518ddcd7050e0f149044740a2b16479413b63fc13c36144f80c73687513dca761ba8642a8ae0",
|
||||
"2d7dc80c19a1d12d5fe3963569547a5d1d3e821e6f06c5d5e2c09401f946c9f7e13cd019f2f9a878b62dd850453b6294b99ccaa068e542993524b0f63832d48e865be31e8ec1ee103c718340c904b32efb69170b67f038d50a3252794b1b4076c0620621ab3d91215d55ffea99f23d54e161a90d8d4902fda5931d9f6a27146a",
|
||||
"77dff4c7ad30c954338c4b23639dae4b275086cbe654d401a2343528065e4c9f1f2eca22aa025d49ca823e76fdbb35df78b1e5075ff2c82b680bca385c6d57f7ea7d1030bb392527b25dd73e9eeff97bea397cf3b9dda0c817a9c870ed12c006cc054968c64000e0da874e9b7d7d621b0679866912243ea096c7b38a1344e98f74",
|
||||
"83bed0d556798f2b419f7056e6d3ffada06e939b95a688d0ec8c6ac5ea45ab73a4cf01043e0a170766e21395f27ab4b78c435f5f0dfe6e93ab80df38610e41158429ddf20296f53a06a017723359fe22dc08b5da33f0800a4fe50118e8d7eab2f83a85cd764bf8a166903bd0e9dcfeeceba44ff4ca4439846458d31ea2bb564645d1",
|
||||
"ea12cf5a113543e39504123036f15a5bafa9c555562469f99cd29996a4dfaaab2a34b00557ccf15f37fc0cc1b3be427e725f2cd952e50af7970dda9200cd5ce252b1f29c40067fea3027ed686190803b59d834179d1b8f5b55abe55ad174b2a1188f7753ec0ae2fc01316e7d498b68ee3598a0e9baaaa664a60f7fb4f90edbed494ad7",
|
||||
"55266358332d8d9e68bd13432088beadf95833aab67a0eb3b10650414255f299e2670c3e1a5b2976159a46c72a7ce57d59b7be14c15798e09ed50fa312a431b0264d7a1396aa6168bde897e208ece53d2cfc83786113b1e6eac5e9bb98984abb6c8d64eebb991903254abc650c999bb9958a5d7937434b869bc940e21b9dc1cc8982f2ba",
|
||||
"4d6104ded730aefe02873f4c741232c8234a6d66d85393aff57fbf56ba6347666988dfc4d58f3cc895a0da598822edeee4533d24ec0ee292fd5e1ad04898ffbc1ff4bef14dec220babcb0f28fffe32a6e2c28aaaac16442bf4feb02917d18bb3a415d84fa9358d5a9852688d846c92271911f934181c30f82434d915f93f155a1ffbf0b125",
|
||||
"eb5f579a4c476af554aac11e5719d378549497e613b35a929d6f36bb8831d7a466aa76de9be24ebb55543f1c13924f64cfd648a5b3fa90387315c16174dbf1e9a183c196d9bb8f84af65f1f8212429aadc11ef2426d07d4716062b85c8d5d2dff8e21b9e62b7fa7dbd57d72633054b464fb28583a56ca13ccc5ddc74dae942492f31731e7046",
|
||||
"ebddec3dcaf18063e45a76ebeac39af85a1adc2818881ccce48c106288f5988365cca2b4b1d7f037322da46840f42bebdcbc7193838d426e101087d8cea03aaff743d573eb4f4e9a71a2c884390769a6503874125d194bee8d46a3a0d5e4fcf28ff8465887d8e9df771d70157e75df3642b331d2778ceb32ceba868640171ab7a5d22eede1ee44",
|
||||
"26d87ec70b57691e3bb359633d3ddba17f029d62cdfe977f5fd42274d79b444a32494d1c01e9f72d03cce78c806df96e93ea78da3a054209924ed765edc4d570f66168dc25ee3114e4017e387440349c8f0a94804761c3055f88e4fda2a49b860b1486a9609095f6250f268b6a4d1aecc03a505632ebf0b9dc22d0755a736faf7ad7000858b5864b",
|
||||
"3880f5cc2d08fa70ef44b1f263fcf534d062a298c1bd5ee2eee8c3265806c4ce50b004f3a1fc1fa5b024aaac7f528c023c8181f67c6e1c357425dc4d573bd46b93a542afa3a19bdb140a2ce666e1a01f5c4d2dcd681fa9f5839b797813c394738d5ee4971386c12c7c117d17c7bec324b760aa30cda9ab2aa850284ba6fa97946f710f02449d1883c6",
|
||||
"3317d2f452105dd3f4a96f9257af8285a80be58066b50f6f54bd633749b49f6ab9d57d45652d2ae852a2f6940cd5ec3159dd7f333358b12f502325df38843508faf7e246352d201280babd90b14fbf7722641c3601d0e458474439973c611bb5502fd0eb3078f87124ca7e1a016fcb6cfeff65f6a565985aca7122cfa8c5a11da0cb47797c5132333179",
|
||||
"f2c5c955d0224e784a46b9125f8fef8a5e1271e145eb08bbbd07ca8e1cfc848cef14fa3b36221ac62006403dbb7f7d77958ccc54a8566c837858b809f3e310ace8ca682515bc655d2a397cab238a663b464d511f02dc5d033dad4cb5e0e519e94a54b62a3896e460ec70e5716b5921bf8396aa86a60123e6287e34570bb01bdc602e113670bf498af2ff10",
|
||||
"180e275205691a83630cf4b0c7b80e6df8fad6ef1c23ba8013d2f09aef7abade1827f23af230de90676240b4b3b0673f8afdea0327330055041741f65560d90348de696d34ca80dfe8afae582fe4879d4594b80e9408fb53e800e01ca58552b905c365e7f1416e51c080f517d6bbd30e64ae1535d59decdc76c6624d737868f49f2f719da39ba1344d59eab9",
|
||||
"c517a84e4631a7f65ace170d1e5c2fdb259841535d88da323e68c0883e6af7b041cfe05908815a5a9d1b14fa712c2c16fadcf1ca54d3aa954d411240df331b2aebdfb65aced84d0b8aace56ec0aa7c13ec7d75ca883b6bcf6db74c9e98463c484a8262684f29910373430651f90ecffe18b072170e61ee58de20e2a6ff67b3ab00fccbb80af943f20b56b98107",
|
||||
"d1a56a5ee990e02b84b5862fde62f69ec07567be2d7ccb769a461c4989d11fdda6c945d942fb8b2da795ed97e43a5b7dbdde7f8fd2ff7154544336d5c50fb7380341e660d4898c7fbc39b2b782f28defac6873523c7c1de8e52c65e4395c686ba483c35a220b0416d46357a063fa4c33fa9c52d5c207a1304ae141c791e62ba6a7374ed922b8dd94079b72b69302",
|
||||
"4720b88d6bfb1ab43958e26827730d852d9ec30173ebd0fe0d273edcece2e788558984cd9306fe5978086a5cb6d37975755d2a3daeb16f99a8a11544b8247a8b7ed5587afc5bea1daf85dcea5703c5905cf56ae7cc76408ccabb8fcc25cacc5ff456db3f62fa559c45b9c71505eb5073df1f10fc4c9060843f0cd68bbb4e8edfb48d0fd81d9c21e53b28a2aae4f7ba",
|
||||
"f4639b511db9e092823d47d2947efacbaae0e5b912dec3b284d2350b9262f3a51796a0cd9f8bc5a65879d6578ec24a060e293100c2e12ad82d5b2a0e9d22965858030e7cdf2ab3562bfa8ac084c6e8237aa22f54b94c4e92d69f22169ced6c85a293f5e16bfc326153bf629cdd6393675c6627cd949cd367eef02e0f54779f4d5210197698e4754a5fe490a3a7521c1c",
|
||||
"3d9e7a860a718565e3670c29079ce80e381969fea91017cfd5952e0d8a4a79bb08e2cd1e26161f30ee03a24891d1bfa8c212861b51618d07429fb48000ff87ef09c6fca526567777e9c076d58a642d5c521b1caa5fb0fb3a4b8982dc14a444732b72b239b8f01fc8ba8ee86b3013b5d3e98a92b2aeaecd4879fca5d5e9e0bd880dbfffa6f96f94f3998812aac6a714f331",
|
||||
"4d9bf551d7fd531e7482e2ec875c0651b0bcc6caa738f7497befd11e67ae0e036c9d7ae4301cc3c7906f0d0e1ed4738753f414f9b3cd9b8a71176e325c4c74ce020680ecbfb146889597f5b40487e93f974cd866817fb9fb24c7c7c16177e6e120bfe349e83aa82ba40e59e917565788658a2b254f25cf99bc65070b3794cea2259eb10e42bb54852cba3110baa773dcd70c",
|
||||
"b91f65ab5bc059bfa5b43b6ebae243b1c46826f3da061338b5af02b2da76bb5ebad2b426de3c3134a633499c7c36a120369727cb48a0c6cbab0acecdda137057159aa117a5d687c4286868f561a272e0c18966b2fec3e55d75abea818ce2d339e26adc005c2658493fe06271ad0cc33fcb25065e6a2a286af45a518aee5e2532f81ec9256f93ff2d0d41c9b9a2efdb1a2af899",
|
||||
"736f6e387acb9acbee026a6080f8a9eb8dbb5d7c54ac7053ce75dd184b2cb7b942e22a3497419ddb3a04cf9e4eb9340a1a6f9474c06ee1dcfc8513979fee1fc4768087617fd424f4d65f54782c787a1d2de6efc81534343e855f20b3f3589027a5436201eee747d45b9b8375e4294d72ab6a52e04dfbb2914db92ee58f134b026527ed52d4f794459e02a43a17b0d51ea69bd7f3",
|
||||
"9242d3eb31d26d923b99d66954cfade94f25a18912e6356810b63b971ae74bb53bc58b3c01424208ea1e0b1499936daea27e63d904f9ed65fdf69de40780a3027b2e89d94bdf214f585472613ce328f628f4f0d56217dfb53db5f7a07f54c8d71db16e27de7cdb8d23988837b49b65c12f1771d979e8b192c9f4a16b8d9fba917bcf74ce5a82aac2075608ba6c2d485fa59864b9de",
|
||||
"5da68704f4b592d41f08aca08f62d85e2e2466e5f3be010315d11d113db674c4b98764a509a2f5aacc7ae72c9deff2bcc42810b47f64d429b35745b9efff0b18c58653461e968aaa3c2c7fc455bc5771a8f10cd184be831040df767201ab8d32cb9a58c89afbebecb524502c9b940c1b838f8361bbcde90d272715017f67609ea39b20fac985332d82daaa023999e3f8bfa5f3758bb8",
|
||||
"71ea2af9c8ac2e5ae44a176662882e01027ca3cdb41ec2c6785606a07d7231cd4a2bded7155c2feef3d44d8fd42afa73265cef826f6e03aa761c5c51d5b1f129ddc27503ff50d9c2d748322df4b13dd5cdc7d46381528ab22b79b0049011e4d2e57fe2735e0d58d8d56e92c75dbeac8c76c4239d7f3f24fb56697593b3e4afa6671d5bbc96c079a1c154fe20212ade67b05d49ceaa7a84",
|
||||
"1d133170582fa4bff59a21953ebbc01bc202d43cd79c083d1f5c02fa15a43a0f519e36acb710bdabac880f04bc003800641c2487930de9c03c0e0deb347fa815efca0a38c6c5de694db698743bc955581f6a945deec4ae988ef7cdf40498b77796ddea3fae0ea844891ab751c7ee20917c5a4af53cd4ebd82170078f41ada2795e6eea17593fa90cbf5290a1095e299fc7f507f360f187cd",
|
||||
"5ec4ac45d48fc15c72471d795066bdf8e99a483d5fdd599511b9cdc408de7c0616491b73924d0266da34a495331a935c4b8884f57d7ad8cce4cbe586875aa52482215ed39d7626cce55d50349c7767981c8bd6890f132a196184247343566fc972b86fe3c5369d6a6519e9f07942f0522b77ad01c751dcf7defe31e471a0ec00963765dd8518144a3b8c3c978ad108056516a25dbe3092e73c",
|
||||
"0d5e74b78290c689f2b3cfea45fc9b6a84c822639cd438a7f05c07c374adced42cdc12d2a9233a4ffe80307efc1ac13cb04300e165f8d90dd01c0ea955e7657332c6e86ad6b43e78ba4c13c675aed83192d8427866fb6484e6a3071b2369a46fba9005f31232da7ffec7952f831aaaddf63e225263531c2cf387f8cc14fa856c8795137142c3a52ffa69b8e30ebc88ce3bbc227597bcc8dddd89",
|
||||
"a0fe36f983259921dc2fa7d89002b3066241d63bfc2448caf7e10522a35562be0bfedc3dce49cfce2e614a04d4c64cfc0ab898873a7fc26928dc1927c009d12f6f9b7a278205d3d0057604f4ac746f8b9287c3bc6b929832bf253b6586192ac43fdd29ba585dbd9059aab9c6ff6000a7867c67fec1457b733f6b620881166b8fed92bc8d84f0426002e7be7fcd6ee0abf3755e2babfe5636ca0b37",
|
||||
"1d29b6d8eca793bb801becf90b7d7de215b17618ec32340da4bac707cdbb58b951d5036ec02e105d83b5960e2a72002d19b7fa8e1128cc7c5049ed1f76b82a59eac6ed09e56eb73d9ade38a6739f0e07155afa6ec0d9f5cf13c4b30f5f9a465b162a9c3ba04b5a0b3363c2a63f13f2a3b57c590ec6aa7f64f4dcf7f1582d0ca157eb3b3e53b20e306b1f24e9bda87397d413f01b453ceffeca1fb1e7",
|
||||
"6a2860c110cd0fc5a19bcaafcd30762ee10242d34739638e716bd89fd537ea4dc630e6f85d1bd88a25ad3892ca554c232c9830bd56980c9f08d378d28f7fa6fa7df4fcbf6ad98b1adfff3ec1f63310e50f920c99a5200b8e64c2c2ca249399a149942261f737d5d72da949e914c024d57c4b639cb89990fed2b38a37e5bcd24d17ca12dfcd36ce04691fd03c32f6ed5de2a2191ed7c826375ba81f78d0",
|
||||
"7132aa291ddc9210c60dbe7eb3c19f9053f2dd74742cf57fdc5df98312adbf4710a73245de4a0c3b24e21ab8b466a77ae29d15500d5142555ef3088cbccbe685ed9119a10755148f0b9f0dbcf02b2b9bcadc8517c88346ea4e78285e9cbab122f824cc18faf53b742a87c008bb6aa47eed8e1c8709b8c2b9adb4cc4f07fb423e5830a8e503ab4f7945a2a02ab0a019b65d4fd71dc364d07bdc6e637990e3",
|
||||
"3e664da330f2c6007bff0d5101d88288aaacd3c07913c09e871cce16e55a39fde1ce4db6b8379977c46cce08983ca686778afe0a77a41baf447854b9aa286c398c2b83c95a127b053101b6799c1638e5efd67273b2618df6ec0b96d8d040e8c1ee01a99b9b5c8fe63fea2f749e6c90d31f6fae4e1469ac09884c4fe1a8539acb313f42c941224a0e79c059e18affc2bcb6724975c436f7bf949ebdd8aef51c",
|
||||
"7a6ea63a271eb49470f5ce77519ed61ae9b2f1be07a96855726bc3df1d0723af3a703fdfc2e739c9d31d25814daf661a23558b50982e66ee37ad880f5c8f11c8130fac8a5d0250583700d5a324894fae6d61993f6bf9327214f8674649f355b23fd634940b2c467973a839e659169c773119919f5b81ee171edb2e5f6940d7551f9e5a70625d9ea88711ad0ed8ab2da720ad358bef954456cb2d5636425717c2",
|
||||
"c5106bbda114168c449172e49590c7eeb827fa4e1a2a7a87a3c1f721a9047d0c0a50fbf244731be1b7eb1a2ef30f5ae846a9f38f0df44f32af61b68dbdcd0226e741dfb6ef81a2503691af5e4b3171f48c59ba4ef91eba344b5b697f261df7bbbb734ca6e6daebaa4a179feb17002823281b8534d55a6531c59305f6e3fd3fa63b747bcf0deb654c392a02fe687a269effb1238f38bcaea6b208b221c45fe7fbe7",
|
||||
"597716a5ebeebc4bf524c15518816f0b5dcda39cc833c3d66b6368ce39f3fd02ceba8d12072bfe6137c68d3acd50c849873150928b320b4fbc31c1456679ea1d0acaeeabf666d1f1bad3e6b9312c5cbdecf9b799d3e30b0316bed5f41245107b693366accc8b2bcef2a6be54209ffabc0bb6f93377abdcd57d1b25a89e046f16d8fd00f99d1c0cd247aafa72234386ae484510c084ee609f08aad32a005a0a5710cb",
|
||||
"0771ffe789f4135704b6970b617bae41666bc9a6939d47bd04282e140d5a861c44cf05e0aa57190f5b02e298f1431265a365d29e3127d6fccd86ec0df600e26bcdda2d8f487d2e4b38fbb20f1667591f9b5730930788f2691b9ee1564829d1ada15fffc53e785e0c5e5dd11705a5a71e390ca66f4a592785be188fefe89b4bd085b2024b22a210cb7f4a71c2ad215f082ec63746c7367c22aedb5601f513d9f1ffc1f3",
|
||||
"be6556c94313739c115895a7bad2b620c0708e24f0390daa55521c31d2c6782acf41156271238885c367a57c72b4fe999c160e804ad58d8e565edbce14a2dd90e443eb80626b3eab9d7ab75d6f8a062d7ca89b7af8eb292c98eaf87ad1dfd0db103d1bb6188bd7e7a63502153cf3ce23d43b60c5782602bac8ad92fb2324f5a79453898c5de18415639ecc5c7974d3077f76fc1df5b956723bb19a624d7ea3ec13ba3d86",
|
||||
"4bc33729f14cd2f1dc2ff459abee8f6860dda1062845e4adab78b53c835d106bdfa35dd9e77219eaef403d4e80488ca6bd1c93dd76ef9d543fbb7c8904dccc5f71509a6214f73d0f4e467c3e038ea639b29e7fc442ee29f57117740576188ada15a739827c647a46b0271817ab235c023c30c90f2115e5c90cd8501e7b286962fc66ffc3fe7e8978746168314908a41998bd83a1eeffda9d714b864f4d490fdeb9c7a6edfa",
|
||||
"ab12faea205b3d3a803cf6cb32b9698c32301a1e7f7c6c23a20174c95e98b7c3cfe93fffb3c970face8f5751312a261741141b948d777b8a2ea286fe69fc8ac84d34116a4674bb09a1a0b6af90a748e511749de4697908f4acb22be08e96ebc58ab1690acf73914286c198a2b57f1dd70ea8a52325d3045b8bdfe9a09792521526b7564a2a5fcd01e291f1f8894017ce7d3e8a5dba15332fb410fcfc8d62195a48a9e7c86fc4",
|
||||
"7d421e59a567af70594757a49809a9c22e07fe14061090b9a041875bb77933deae36c823a9b47044fa0599187c75426b6b5ed94982ab1af7882d9e952eca399ee80a8903c4bc8ebe7a0fb035b6b26a2a013536e57fa9c94b16f8c2753c9dd79fb568f638966b06da81ce87cd77ac0793b7a36c45b8687c995bf4414d28289dbee977e77bf05d931b4feaa359a397ca41be529910077c8d498e0e8fb06e8e660cc6ebf07b77a02f",
|
||||
"0c18ab727725d62fd3a2714b7185c09faca130438eff1675b38beca7f93a6962d7b98cb300ea33067a2035cdd694348784aa2eda2f16c731eca119a050d3b3ce7d5c0fd6c234354a1da98c0642451922f670984d035f8c6f35031d6188bbeb31a95e99e21b26f6eb5e2af3c7f8eea426357b3b5f83e0029f4c4732bca366c9aa625748297f039327c276cd8d9c9bf692a47af098aa50ca97b99961bef8bc2a7a802e0b8cfdb84319",
|
||||
"92d5909d18a8b2b9971cd1627b461e98a74ba377186a6a9df5bd133635250b300abccb2254cacb775df6d99f7c7d0952653c28e6909b9f9a45adce691f7adc1afffcd9b06e49f775364cc2c62825b9c1a86089080e26b57e732aac98d80d009bfe50df01b95205aa07ed8ec5c873da3b92d00d53af825aa64b3c634c5ece40bff152c331222d3453fd92e0ca17cef19ecb96a6eed4961b627aca48b12fecd091754f770d52ba861546",
|
||||
"802f22e4a388e874927fef24c797408254e03910bab5bf372320207f8067f2b1ea543917d4a27df89f5bf936ba12e04302bde23119533d0976beca9e20cc16b4dbf17a2ddc44b66aba76c61ad59d5e90de02a88327ead0a8b75463a1a68e307a6e2e53ecc1986274b9ee80bc9f3140671d5285bc5fb57b281042a8978a1175900c6073fd7bd740122956602c1aa773dd2896674d0a6beab24454b107f7c847acb31a0d332b4dfc5e3f2f",
|
||||
"3844fe65db11c92fb90bf15e2e0cd216b5b5be91604baf3b84a0ca480e41ecfaca3709b32f8c6e8761406a635b88eec91e075c48799a16ca08f295d9766d74475c47f3f2a274eae8a6ee1d191a7f37ee413a4bf42cad52acd5564a651715ae42ac2cddd52f819c692ecdef52ecb763270322cdca7bd5aef71428fa73e844568b96b43c89bf1ed42a0abf209ffad0eeec286c6f141e8af073ba4adfbbdeda253752ae36c9957dfc905b4c49",
|
||||
"329377f7bf3c8d74991a7d61b0cf39baff5d485d79751b0d5ad017d23bec570fb19810105bab79ab5acb102ab972165224d4ec888ec7de5148077fa9c1bb6820e0d91ae4e2591a21fec2f820606ce4bafc1e377f8dc3a5bd1a9e2772a57abccd0b757164d768872c91d02789545ab5b203f688d71dd08522a3fd2f5bcd7df507aebf1ca27ddff0a82afb7aa9c180008f49d1325adf97d047e77238fc75f56356de4e87d8c961575c9f6362c9",
|
||||
"f7f269929b0d71ea8eef7120e55ccba691c582dd534692abef35c0fe9dec7dae973cd9702e5ad420d278fe0e653fdcb22fdcb63148109ec7e94f2d0750b28157dd1764376ae10fdb0a4aef3b304bd82793e0595f941226a2d72abbc929f53134dc495b0d65ced409914f94c2523f3dfbbdeeac84ae247ab5d1b9ea33dce1a808885a55be1f3683b46f4be73d9b62eec2585f690056858dfc427aabf591cd276724885bcd4c00b93bb51fb7484d",
|
||||
"ac022309aa2c4d7fb628255b8b7fb4c3e3ae64b1cb65e0de711a6def1653d95d8088871cb8905fe8ae76423604988a8f77589f3f776dc1e4b30dbe9dd262b2187db02518a132d219bd1a06ebac13132b5164b6c420b37dd2ccee7d69b3b7fa12e54f0a53b853d490a68379ea1fa2d79762830ffb71bf86aab506b51f85c4b6a41b69325c7d0c7aa85b93b7144489d213e8f33dbb879fce22849865337b620b155cb2d2d36a68832889e30194d36d",
|
||||
"d009c2b78a8f02e5e5dbb586ef71fc324b375092e15913ca1a5bfd22d516baadb96867bee3562e77c4a4852344a1a76c30728be5e22400b4cc41711f66754c246a520498d8c24f0205b9c873748dbeb67fe1ad099ad04cf89f4b517f0aa481136d9f6de2d727df01c6aa4099da59d4382b51e25fd47c33d9842c32b62331e50794bfe8b61b3ba9de1b8b704779c6d65edff3af00f121ab4a7ea384edabe47c6d0098a48991f387ca4444135ec59d46",
|
||||
"c00bab36cce69899817d1425016d222d7303197ed3e3fdcac744705e7f178a1ac745968900f69299163e19b3161f3e0a4cc55aa2e4e71e0ee6ac427d1f4d14e063f68d303ddfbb18118335cfa7a6a90d99c38319ee76f7a884846a9e0b68030bf28e78bfbd56359b9368842814da42b04cb0e307d5d846dc22f049147bae31b9a956d17676a8cc348dafa3cabc2007a30e730e3894dddf9999fb8819086311f0703e141613ed6dcd7af8510e2dc435b0",
|
||||
"c9789152a9fc29698d49ed95f09bd11b75f18a8c5615a73dbe54ae5e550027fd0ae6a8b60667040c1b12de3d1ee3f6bf061c78c951a3210effc912e19f482dd4de152063c588c44903bc11761706fd935afa040df085b08144d83d0dde32b46ab52f4fae98ac116c7ff11d7f553450c2e37b9c5f0b1dd9e0b8640a24cba6f2a5246c41f197f46e3dc8a29131c79bef3351c6e277a0a34442274d546ccd058891277473d668420f121750d19cd684267405",
|
||||
"06a15a0731ce52557e368bcbaa11ef3399299e36fb9f2eda6e5726907c1d29c5c6fc581405ba48c7e2e522206a8f128d7c1c939d1132a00bd7d6366aa82724e968964eb2e373563f607dfa649590dcf5589114df69da5547fef8d1604cc4c6de1ed5783c8746918a4dd31168d6bc8784cd0c769206bd803d6ca8557b66748770402b075ef44b38157d4c0da7c6281725a2065d087b1f7b23455fa673bdeeba45b983311c44eabe9ef4b7bde3420ae9881863",
|
||||
"d08aacef2d7a41aec09473bd8a44f628e15addb7b9e5b77a1e09c8ab4942f379a0bfcb324d580b774666f18ae78dd36710824ff12393f059068fe4b559c53662c2b0e6c69e23785c8f32554e837ec1714bee902e60737b639dd933af4f68cb9d7de77e1f3b28e5b122891afce62b79acd5b1ab4ba411662cc77d806449e69c5a45a143b742d98ac84a0826d68433b9b700ace6cd472ba2d58a90847f42ce9c43f38ffc017db4bf40450b2eee1f4594dc740c0f",
|
||||
"6a6058b0a498b7ea76a93c646eb9b8629f0cba4a0c726420c5f67ba9b0412cade356abdf0a4fb94384bad32ce0d5dd9e23dcaae1d6f28ff8683616b30f1392890c67b3a2c04b360893b801f127e527e4da82e239f4c878da13f4a4f1c76db07190e77ec123995168102fb274434a2d1e12913b9b5cbab4aacaad2bd89d88b3ca2b8e60dacf7c22c9379097ff60880f552e320ca3b571994f52534470feee2b39e0dadb5cd88257a3e459a4cc6f12f17b8d54e1bb",
|
||||
"adeced01fc5671531cbb45679f5ddd42b3a95151677b6125aaf6f5e8f82fbabaa5ecf7c3552c2458587224f0042870f178f5fca5465250e75d71352e652eeed23cdb7f915f5ebb44099b6db116ca1be45530ac8ed32b7f161d60ed4397ad3d7d649ae6bf75ca5bec891d8e595605be9764f3a03965e1fe0eaffbf212e3df4f0fa35e08ff9d0091e6d4ac4748edfe43b611085a6ffec163014655fdd839fd9e81b63b1fa8cae4ec335ec343289758e389a79ceedfae",
|
||||
"d014592f3a83ba40af366f137c674724916c3cdd3f6cf9d4c5c7c8d6d51ebf26e315e2c12b3546be56fb52382904046ecbd2f5b883aa4ff473de6f0c26ab862c3fa34bf3d880cc1911ce39a4088c6617c179dc5faf68a2c488bbde12d67b50f73abcfab0e3b062e68c95363e11f5f1de8ec36ed01ea21442518089045df67d346135283ad5b3fff80cf57f20876849f6db9fa139728358415a90610f69ec720fc92d8234e3e122551e9df2c644c4a2c4e3734d07de8e",
|
||||
"c0d0c37838873ba8757d6e41b409605043bc1635edcd731219587676d94217e9f0ab44b71de25000661ce7303b7015f45e6eaa7b7ebef92b8f4a34c902c908d2172185505fa33aca5a41be83079316cdfdd430fc2c45f505f85d867e6d516f7e1bf19c001d9f43018968aab65ec031b3801399231c83ec9e622dab5629922a6b424cab938c135ff7310501c2c02971bfd2f577e25904d1a618baf0859f77f4e8b1d0cde9544e95ec52ff710c0672fdb3d891feeea2b017",
|
||||
"7022e7f00902219ba97baa0e940e8ac7727f58955aa068c29680fac4a16bcd812c03eeb5adbcfe867a7f7c6b5d89f4641adb9173b76a1a8438866f9b4f640ce2aedf5f1080c890bcf515b4be4e3e512352f1e5323c62ec46cb73f3d71be8235fee55a154763f7c3f9aeb61ffd28f4cd93d3310f608e2133586bf1ab3f102de96f64c68a4668de8acb2a76a7ce0cddddc8fa3df5e9d230823da16ed9ebb402d36e38e6e018795e5a71517ecab5f9ca472b9ced8ff69d2d195",
|
||||
"acaf4baf3681ab865ab9abfae41697141ead9d5e98523c2e0e1eeb6373dd15405242a3393611e19b693cabaa4e45ac866cc66663a6e898dc73095a4132d43fb78ff7166724f06562fc6c546c78f2d5087467fcfb780478ec871ac38d9516c2f62bdb66c00218747e959b24f1f1795fafe39ee4109a1f84e3f82e96436a3f8e2c74ef1a665b0daaa459c7a80757b52c905e2fb4e30c4a3f882e87bce35d70e2925a1671205c28c89886a49e045e31434abaab4a7aed077ff22c",
|
||||
"84cb6ec8a2da4f6c3b15edf77f9af9e44e13d67acc17b24bd4c7a33980f37050c0301ba3aa15ad92efe842cd3ebd3636cf945bb1f199fe0682037b9dacf86f162dadabfa625239c37f8b8db9901df0e618ff56fa62a57499f7ba83baebc085eaf3dda850835520344a67e09419368d81012168e5de5ea45158397af9a5c6a1657b26f319b66f816cd2c28996547d697e8df2bb163ccb9dda4d6691dffd102a13667ab9cde60ffbfb872187d9c425a7f67c1d9fffff9276ed0aeb",
|
||||
"6a52c9bbbba454c14540b2be58230d78ecbeb391646a0c6fcce2f789086a78364b81ae85d5396d7cfa8b46bda41e3083ec5cf7b4c47dc601c8a697df52f557defca248506dbebab25657f5a561d09625b7f4b2f0119a12beeac087efc9d350a735c35d2431c1da7dda99befb17f41a3dc4da0f00bb95366be128538ce27763d81f832fe3c1d4efc07b5b08ad8dc9e65fb5e48546664e18cb2d3bb3fe1f56fa7aae718c5e3bbdeaf70e15023f6a25b72a2d177fcfd04211d40664fe",
|
||||
"c3c4d3b31f1f5f9538923df3478c84fffaef411520a542da9a220ee4132eabb9d718b5076fb2f985485e8ba058330aed27ddfd3afa3db34aa60301088caec3d0053828c0c2bc87e2e61db5ea5a29f62fdad9c8b5fc5063ec4ee865e5b2e35fac0c7a835d5f57a1b1079833c25fc38fcb14311c54f8a3bd251bca19342d69e5785f9c2e43cf189d421c76c8e8db925d70fa0fae5ee3a28c4047c23a2b8a167ce53f35ced33bec822b88b06f41558c47d4fed1bfa3e21eb060df4d8ba1",
|
||||
"8d55e92136992ba23856c1aea109766fc44772477efc932b3194af2265e433ed77d63b44d2a1cff2e8680eff120a430fe012f0f09c6201d546e13ad46fc4ce910eab27bb1569879abed2d9c37fae9f1267c2216ec5debcb20d4de58461a621e6ce8946899de81c0add44d35e27b7982a97f2a5e6314901caebe41dbba35f48bc9244ca6dca2bdde7306435892f287036df088633a070c2e385815ab3e2bfc1a47c05a5b9fe0e80dd6e38e4713a70c8f82bd32475eea8400c7bc67f59cf",
|
||||
"5016284e20362610fa05ca9d789cad25f6d43263787e7e085476764ce4a8908ce99b262b375e9d106170b1bec1f473d5e777e0c1896533040e39c8c1465e07907ef5860e14e4d8310013e35f12090e0bfc687474b1f15f3dd2033a0edac5246102da4deec7e188c3517d84d9c2a0a4497a4c5f82a30f1ba009e45ee6eb3ab4368c720ea6feee428ffd2c4cc52debb8d634a64176572c72368f94a66689f23f8a01218f532117af5a8060d140e7ca435a92882fcb5630ebe14a4805f1dc83",
|
||||
"05456ec59b8d41bbd736727976b96b38c43827f9e16169be673ff37870c2ecd5f0d1ea1a136be4cc7b047a02a4421d484fd2a12ece418e42ee391a13a0b1df5a0162b29ab70d3fe3e04ba6ab26b37d62b7cf05a5e2f033611bf970b8e1f30e198e483e740fa9618c1e8677e07b61296b94a9787a68fba622d7653b5568f4a8628025939b0f74389ea8fced6098c065bf2a869fd8e07d705eadb53006be2abb716a3114ceb0236d7e916f037cb954cf977720855d12be76d900ca124a2a66bb",
|
||||
"eb6f60b83fcee77060ff346aaf6ec34d82a8af469947d3b5074cde8eb26566eb1fa039bcc707738df1e95869bd827c246e88436f0614d9834ead5392ef376105c4a9f370071cdeaaff6ca0f18b74c3a48d19a717253c49bd9009ccbfdd5728a08b7d112a2ed8dbafbbb46d7a75dc9a05e09bfde1a0a92d74a51887f9d123d7896e9f9d0057b660ed7d55454c069d3c5260411db4cdc67e7b74f680d7ac4b9dcc2f8baf72e15e6b3cafebcdf449a6436ed2c398b675f79c644747c57553bf7ea2",
|
||||
"187a88e88514f6c4157c1ba40b442baae1ae563a6c989277443b12a219aa484cb9fa8adbb9a29d429f50155321b15664926317477079c7060dfdaa84c1d74bba78892c34e6f21ad35208d2ae622012401696bff5cd57b6485944b3db7b9071fa5f57fbfb1085d91bb9cff5808d662cdc6c8157249478262c44b7fbc397ed42a4977b202e817717bfccc9f0467294062313f7705251ed09573f16d23429361fada259dfb300369c4198f07341b38e84d02cdb74af5de6aab1fc2026208ea7c418c0",
|
||||
"be31bc96606d0fab007e5caeded2f1c9f747c759777e9b6eef962bed49e45a1d4fc993e279d024915e600865ecb087b960584be18c41114d3c43f92169b9e0e1f85a0ebcd4e196376ccdc920e66103cd3b1c58407d0aafd0e003c4e341a1daddb9f4faba974362a32f35db83384b05ae8e3322d728893861afd8b1c940de5a17f691e763ce4969b6d94f67fb4a0235d100225bd8602f291388f0ca4a568748ad0d6040f1262eac2aede6cd27419bb78a394c1ffad72c262be8c3f9d9619d633e51d0",
|
||||
"4d83d85ca838b4518588f2a90228a4dd18f14dd5b4c012d26298a97d848abbd825d221d02cceb6e8c701b4ad00e1dee4889b5c533e4bb60f1f41a4a61ee5478be2c1b1016c30345afd7a5253668260515e70751f22c8b4022d7fe4877d7bbce90b46531507dd3e89549e7fd58ea28f4cb23d33662bd003c1345ba94cc4b06867f778957901a8c441bee0f3b12e16463a51f7e50690356971dd73a686a49fda1eae46c9d54fba262811d698025d0ee053f1c58591c3bb3cbde69de0b31549ef5b69cf10",
|
||||
"cdeb07d36dc5f9a1cd717a9e9cca37a2ce93caa298eee63571f7d6c5fde2a11c666cf53cf2dcb41ca2ea2319e7230ca68e38c647905928713a13982bf47fe33d7095ebd50b2df976208920a43eb2e29b942f32467403c45cea18bf44e0f6aeb155b48a8e5c471fec972a9d62f7ae093d2758f0aaec7ca50cb4725bfa219f1a3a46ad6bde7361f445f86b94d66b8ece080e56c510250693a5d0ea0ae87b4421860b853bcf0381eae4f1bf7c5c0472a93ad18407bc88475ab8560d344a921d3e86a02da397",
|
||||
"a598fad52852c5d51ae3b10528fc1f722e21d44fbd42ae5acdf20e85a28532e646a223d27fd907bfd38eb8bb75175636892f8242877aab89e8c0824d368f3339ce7a82aa4e5af6db1f3b588a4d667a00f67bee37cfd2724dde06d2909fb9e58d892f4cfd2c4ca85acdf8256f5458b030a6bda151154ff2e6d7a8da90b54a2884c8a99fab5a4ac211ff23dc0975f4f592fd1b6b9dc7783bdcd2d4ca4e68d2902f2013e122cb62e2bff6b0a98ec55ba25837e21f1cfe67739b568d43e6413dab2bd1dc471e5a",
|
||||
"17b68c74c9fe4926e8102070916a4e381b9fe25f5973c9bd4b04ce25749fc18931f37a65a356d3f5e5a1ef125d546f4f0ea797c15fb2efea6fbfcc5739c564693d47adeb12dcb3d98a2830719b13247792cb2491dca159a28138c6cff925aca42f4fdb02e73fbd508ec49b25c60703a7595a3e8f44b155b371d525e48e7e5dc84ac7b17c52bf5e526a67e7187234a2f19f57c548c70fc0b27183df73ffa53fa58b658034c896fa791ae9a7fd2620f5e46ce84c842a6e60e9324ae4db224ffc87d9617cb85ca2",
|
||||
"b9e4267ea39e1de1fed0579f93bb351007c9f8fcdd811053fae33f09e2753d7428f04e1a9efcd45ea701a5d87a35b3afb2e6b65365dee6ead0bbb611b7797b212ac688653f542e604a39df277f12514ddfee3b4e27b98395c2cd97a203f1f1153c50327965770802ec2c9783edc428271762b275471e7ac65ac36523df28b0d7e6e6ccc7674268a132a63411fc82c0738dbb68af003b769a0bf9e6587b36476cb465350fee13f88ea355d47ffac7b0f964f4139db11b7642cb8d75fe1bc74d859b6d9e884f75ac",
|
||||
"8ca704fe7208fe5f9c23110c0b3b4eee0ef632cae82bda68d8db2436ad409aa05cf159223586e1e6d8bdae9f316ea786809fbe7fe81ec61c61552d3a83cd6beaf652d1263862664df6aae321d0323440430f400f291c3efbe5d5c690b0cc6b0bf871b3933befb40bc870e2ee1ebb68025a2dcc11b68daadef6be29b5f21e440374301bde1e80dcfade4c9d681480e65ec494a6af48df232c3d51447b9d06be714949249c44c43cf73ed13ef0d533e770284e51369d94ae241a5fb2f163893071b2b4c118aeaf9eae",
|
||||
"4fd8dd01012bb4df82bf42e0683f998e6f52dd9c5617bae33f867d6c0b69798cead8179346d70acc941abbbdd26e3229d5651361d2252c72ff22db2938d06ff6fc29a42fdf800ae967d06479bc7bbb8e71f40b1190a4b7189ffc9a7096cdb76d40aec424e1388e1eb7ef4ac3b34f3f089da8fda7d1927f5d775c0b2801d22dd1265c973158f640cec93edfed06dc80b20ef8c496b98289d54d46ccd205951cbb0f4e7daeb866b60bacb483411e4382b6f04d472843186bd0e31fbaa93e5c901ec028efafeb45fc551a",
|
||||
"e9ee1b22b04b321a5fdd8301627011f583887d77560fb0f35552e207561f81e38ac58a0d0aeaf832d1ee72d913720d01f75574e9a321864fe95f4d0d8f0b8db97649a53e71e940aede5c40b4b9105daa42a6fb2811b61209247534cbaf830b07abe338d75d2f5f4eb1c3cf151e9edabe2c8d5f6fff08fac1495ef48160b100d30dcb0676700bcceb28723a29980ab0766a93abb8cb3d1963007db8458ed99b689d2a7c28c788743c80e8c1239b20982c81dadd0eed6740c65fbc4ef15c7b5569cb9fc997c6550a34b3b2",
|
||||
"ec01e3a60964360f7f23ab0b22e021815765ad706f242265ebc19a2bb9e4eac94393952dcf61aae47682671a10f9165f0b20adf83a6706bfbdcf04c6faba6114653a35584267267873291c6fe7ff5f7695243143421509502c8875aafa9e9afe5be5ef2c851c7f35d69be5d3896000ccdbbfab5c238bb34d607cfe2d55d748880545b4aa7ca61137992925189025c62654b1f20d49c3ccd75aa73ce99cd7258dabedd6480a9f5185531fc0118beb68cc0a9cd182f6973287cf9252e12be5b619f15c25b65c71b7a316ebfd",
|
||||
"db51a2f84704b78414093aa93708ec5e78573595c6e3a16c9e15744fa0f98ec78a1b3ed1e16f9717c01f6cab1bff0d56367ffc516c2e33261074935e0735ccf0d018744b4d28450f9a4db0dcf7ff504d3183aa967f76a507357948da9018fc38f150db53e2df6cea14466f03792f8bc11bdb5266dd6d508cde9e12ff04305c0295de29de19d491ad86e766774bb517e7e65befb1c5e2c267f013e235d8483e177214f89978b4cdc81aa7eff8b39f2825ad3a1b6ac1424e30edd49b067d770f16e74dd7a9c3af2ad74289a676",
|
||||
"00e40f30ae3746edad0f5dd03d0e640933cf3d1694804c1e1ed6399ac36611d405196ee48f129344a8512feda16a354517871322bd5d9c6a1b592933eab531923efb393ffb23d9109cbe1075cebfa5fb917b40df028a621460ff6783c798792cb1d9635b5a6f84ec13918fa302924649b5c7fcb1f7007f0d2f06e9cfd7c27491e565a96c68a0c3644f92cd8f38857258c33801c5d537a83dfe583cba59d7eec7e394199c0a2660a62fabe3ed2099d57f315a6cd8de1a4ade29d977f15d65759cff433e5ac0c182aef3761163e1",
|
||||
"3c5ea24d0d9b618294a263f062b2414a722be4eb10dfc346a6ec3b821d7396eba61cd6ef33618b04cd087a811f299d4606820227f16000d7c839062b96d3e3f59cd1a082448d13fc8f56b3fa7fb5f66d0350aa3b72dd7c165d590282f7da2e12cfe9e60e1796122bb8c2d40fdc2997af634b9c6b127a893dfb3467909378300db3da911be1d7b616bb8e0572433e65527e15d936500a2c60e9f9909dcf22ab5e4b6700f0238c205b4a813626fac3d945bab2637fb08203044a73d20c9a3fcf7c3fc4eb7807c3276dd5f73ce89597",
|
||||
"9271aeeebfac46f4de85df78f1bfd36136aa8905e15835c9e1941176f71e3aa5b1b131843d40479735e23e182a2bd71f66f6149dccb7ed8c16469079dc8590bbf165374951785f4531f7e7361de62f936cfb23a2b5bdf186632e7042a0dd451fdc9b7208f923f3a5f250ae590ec348c63a16c3aacaf7379f53b5dd4152dcd40d23e683e2156e64c592ffc07e2cd6bbeebef4dd590b2f6b2bcbf08fcd111c079f5c4033adb6c17574f8756ecd87be27eff1d7c8e8d0324438d59ae171d5a17128fbcb5533d921bd044a2038a5046b33",
|
||||
"4e3e533d5bcb15793d1b9d0468aaee801f32fdb486b11027183553a09ddbee8213924296f2815dc61577297459e834bf1c7a53f87d43782209e589b8295219ba7073a8fff18ad647fdb474fa39e1faa69911bf83438d5f64fe52f38ce6a991f25812c8f548de7bf2fdea7e9b4782beb4011d3567184c817521a2ba0ebad75b892f7f8e35d68b099827a1b08a84ec5e8125651d6f260295684d0ab1011a9209d2bdeb75128bf5364774d7df91e0746b7b08bda9185035f4f226e7d0a1946fcaa9c607a66b185d8546aac2800e85b74e67",
|
||||
"b5d89fa2d94531093365d1259cc6fe8827fea48e6374c8b9a8c4d2209c280fa5c44958a1847222a692a59e6aa2696e6cdc8a543dd89b0ce03bc293b4e78d6ef48e1839694ccd5c65661143095c705b07e3ced84a0f5959114dd89deb956ab3fac8130eb4a878278205b801ae41a29e34146192308c4e759b374757b0c3b00319bce92a1b95a4d2ee179fd6714ff96155d26f693a5bc973f84ac8b3b91e3926276297532d98b46992a3f104c08100bf1671c43134bac280c617da711e90a0100137525375ebb12802a428885ae7fce6514a",
|
||||
"40e3d8048fc10650cb8a7fc2e7113e26dec34f9ca2d5129cd10a8e8e44d113d61ee48c7d003e19fd307fc6debd70feb30243f298c510ccc4418355ce143066f067ad7c6de7288c3080e7ad46a23c8d34deb55a43e652fe90444ad3c57d3ec1e1c489d63ef915a24bc74a7925a0a7b1e1523f21ca8fee78df24e3d0a68d0013423db97c280799a0618229c0f2c167289a891e5c8d6661ab21285951c31710e3b5fe55f6347fe16d9b40507948a59252efeb616df83e5c098b07d0a7247cd371daff0e50491c582503fd89f79ba94d6af9ed76",
|
||||
"1fa444de01dd3901e2b4684e3d7a799ffa02d85afd35fb30fe4c9d672837bee6dd8a3b8608b4bb5e589220ad5a854f46b46e41c6d57ad124a46beab4169ff69fee7e3838a6165e19dad8eb5d7bf53d4edd3cd2769daf219510a02fdd2afe0c0e1da3cd30fcd1aa88b68965586f07a25a1720fbd90a096ea30fc8e945e3637d7857c8a9c0ab4154ffb2000e57b5f9adfa4e4eaf8065bc3c2b2e75f495963325588785a6ce417dcddffd299873b15dcccca128d63cd4eeeadb64cda28099a9ad7c80d34844901f26b88b00b9aafeb2f90286d29d",
|
||||
"fde0a0d9d813983bd1f55cf778a003a2023b34a555322ab280584537bc6bdd844d22a7d6066c18da83ec09f3d8d5a1aab4be0d5ce19b436052f6e259a4b49017a1f47f1fe2bf115d5bc8599fb216351c60dd6b1bedb2e6f4dcadf424b833501b6f099cbfad9e2290680fb69c25032b42a6274f7cb9b5c5950401354838a45f7cb77b95bf54718e2f3d3d9fb91eb2311903980277396398d9736d8e92fd838594ac8a537c6c529db5a8a4f89290e6ba6f20ac0e5ed6fef40901d0e0e8e3e502990811f9acaae555dd54eb1bcd96b513e2fe751bec",
|
||||
"9f8e0caec87858599f5ab29bff86da78a841a918a023a111098687ecdf2747612d3f3809d9ca400b878bd4f92c43a1004f1c17c7f19a3cd1ce449bd2b23aff551623c37dd8c0be56bf3fd857b500c2b9f9ccea62481944090a3cf3b6ee81d9af8eeb60f65ef150f9fa4d3ed6ce4762d3d4f174ee8ccd460c25cafac0ea5ec8a6a4b2f9e8c0520cb7061155e532cb65f188b01e4b9086db951f504b060c296b326b3fc1c590498ecce594f828f4a10ea416675720ae505295d38a791bd0e93f428448a8f4c1fc0af53604a9e8255384d29ae5c334e2",
|
||||
"33d1e683a4c97ee6bbaa5f9df1a88cb53b7f3c157b6045d70a56fda0ccbd3a1fa1f049cd564da072b53f415bf5fb843771c1d2551fd075d33377362b2f7c0645f9723123d11975991db8a2b518f02e2c7c30342a044754290bae2c77496d755e5981f12e6b0a0174280b958bf11ed628a9062775993ced04bf752ea8d165e3ac2177d7cd1b9371c44efa98f0b3e68602a839d384eec007979f46429dafb138cbc231ad928a9f65f7d66fac77416395e8f1debaaf76ec2e4e03e8674102cd26f614739f3ec9f949033df1fb97e87c2326d65aef94ed5f",
|
||||
"180048f09d0b480887af7fd548a85abf605440c1ddde6afe4c30c30670233f7bf928f43b4681f59279ebbda5e8f8f2a1abefdee129e18ac60f9224e90b38b0aabd01308e0a27f41b6fb2ee07ee176ec9048c5fe33c3f7c791469c81f30e28170585b9f3e7e3c8c2e9d74370cb4518f13bf2dee048cbd98ffa32d85e43bcc64a626b40efb51ce712925fdd6fee006dc68b88004a81549d2121986dd1966084cd654a7c6686b3bae32afbd9625e09344e85cf9611ea08dfce835a2e5b3726e69ae8a76a97db60fcc539944ba4b1e8449e4d9802ae99fae86",
|
||||
"13c0bc2f5eb887cd90eae426143764cf82b3545998c386007cca871890912217aa143ac4ed4ddb5a7495b704aa4de18419b8664b15bc26cfc6596a4d2ae408f98b47a566476d5802d594ba84c2f538def9d016661f6404bb2337a3932a24f6e30073a6c9c274b940c62c727242e24466084a3ea336365d71ea8fa6499c0ea8d59eea505f1126b99c795023c4963aa0d99323d0391e8701110edf551b2d3799e1063ca443f1add162156e445502ca1a052fe70c289838593b58839fc63de128a03e2bbf389e22ae0cf957fd03315ee407b096cc1cfd92dee6",
|
||||
"6f1eb607d679efef065df08987a1174aab41bdac8aece7726dfa65805d6fff5b3d17a672d96b770dc32165f144f0f7324822a5c87563b7cd9e37a742ae83ef245d09006d91576f435a03476f509ea2936636232f66aa7f6cdf1ac187bbd1fcb8e20f8791866e60ed96c73374c12ac16795e999b891c64507d2dbd97e5fc29fac750ad27f2937cbcd29fdafccf27ab22453834d475f6186eaf975a36fad5c8bd61c21da554e1ded46c4c39765dcf5c8f5ccfb49b6a4dc562c919d0c7d8940ec536ab2448ec3c9a9c8b0e8fd4870cad9de2577c7b0c38563f355",
|
||||
"dcdd993c94d3acbc555f464871a32c5da6f13b3d5bbc3e34429705e8ad2e76393fdd96a69a94acb652f5dc3c120d41187e9aa919669f727c4868013b0cb6acc165c1b7706c52248e15c3bf81eb6c147619467945c7c48fa14a73e7c3d5bec91706c567145342a026c9d97eff97ec672c5debb9df1a998083b0b0081d65c517b3e5634c95e347e781aa30ca1c8af815e2e494d844e847fdcb41622894a518dc36571123a40bfdbe8c4f4cff44d83c61dd9dcd24c464c53b395edb31efee9f3aa080e87cdc3d22d613ae84a53c9249c32c96f9a3bc4629bb126a70",
|
||||
"49971f9823e63c3a72574d977953329e813b22a8387cd13f56d8ea77a5d1a8a20012632d1d8732bbcb9f756b9675aab5db927beacab7ca263e5718b8dfa7b2eed9a91bf5ed163b16139d45f7b8cc7e3f7bdda6202106f67dfb23b7c315ee3e17a09d466b1e6b13e7c7428184a979f5358667b4fa8bd40bcc8ea46058db44587a85377ac46bf155136c09ac58cb6c27f28e17028c91e7e8f74d5b500e56293b316974f02b9d9ea205d9b6ac4cfb74eb8eb0c944577fd2f41316368307beab3e327bf7dbaa0a4428836ec4e895dea635234abeaf113ceeadac33c7a3",
|
||||
"c57a9cc958cee983599b04fe694f15fb470fcbc53e4bfcc00a27351b12d5d2434444253ad4184e87b81b738922ffd7ff1dc1e54f39c5518b49fb8fe50d63e3935f99e4bd125e8dc0ba8a17fd62de709339a43fabe15cf86d96a54010112170c340cfac4132182eed7301402bc7c8276089dec38488af145cb6222525894658f03501204b7a66aba0be1b557b28a2f652d66f7313ed825ecc4d8596c1be7420d4425b86a1a90a5b7f30d0f24e0d1aae0eb619ca457a71699e44be612a4011c597ee80b94d5507e429d7fc6af22579cd6ad642723b05ef169fade526fb",
|
||||
"0568a672cd1ecbaa947045b712e2ac27995392fbef8f9488f79803cbee561c212287f080eca95adb5ba42739d78e3ba667f06045d87850d3a0499358649caa257ad29f1a9c511e7054db20554d15cbb55ff854afa45cae475c729cea72ede953522031865bc02b95589ed4d9841c552a8cc94904a93ed09ed77222f6c178195056be59bc4e96a815adf534e6b466fb47e262ff79c803c157a21b6e2269c2e0abeb494113cd868d8466e82d4b2f6a28b73645853d96bc9242515d803e33294848d3fe42fdff68da53c03491636beede47ff1399dd3d54a5e914d55d7adf",
|
||||
"3f19f61a4cd085796731ac9f85a75a8bce77031932c31762d87d8b8d07b8bd19ff78d6b7d1bd1e87f3a4f41aad03b6c4d17a6cbc86be55f7c8b88ada047bb04f8d49f1c34bcf81cc0f3389ad01a758fc7eeb0072aa9ad1481992bfdde82e438e75590a4423832dfbe3756e2229ea873bc3606e6d72174cb2163bf40b5d49c81009dab85ecc03e311351bbf96e32c030a2b276a7698cb25bc2c967acb3213161a1fdde7d912cd6a804490f8056c47da1333f6e35c41e749c2c23919cb9af5eec5652e6e072b034fb1682e9aaa194a9c0bd456ea0b008d14dbce37967a7a8e",
|
||||
"705f98f632d99d3651793825c38dc4deda56c59eac539da6a0159c83131cf8ab6f2ee0c3b74111fde351f7aa1a8c500a0cecab17c212d2c58ca09eae608c8eefc922b9902ef8d6832f799ba48c3c28aa702b3242107edeba01daafe424406a3822965056cfe8783455a671e93b1e2eae2321364f1871471c82124df33bc09e1b52882bd7e1c4c7d0b2f3dd4a28c2a002a43246768af0700f9659de99d62167be93177aabf19d678e79e9c726ac510d94e74873eda99620a3961930cd91937c88a06d8153d64fd60da7ca38cf26d1d4f04a0df273f52127c53fdc593f0f8df9",
|
||||
"ea6f8e977c954657b45f25480ff42c36c7a10c77caa26eb1c907062e24fbca5aebc65cacca0de10abea8c78322f08672e13d8ac16996eca1aa17402eaea4c1cc6c800b22dc18cb8d620192d74bac02c07b5cfa61e513c7f28b7e29b9700e0e442720bf4c669d4995da19d19f841d9eb68cc74153592591e3bf059ef616b95305aa453b32fe99a91afb35bd482cf2b7aa42702837a53be3c38883d2963020e347556f841254ec6b85854485fe8c520b05f2ea67a9bf3981555c20991e2bacd4db5b418228b6002d8d41c025cb472bf5443aaa885974a408ea7f2e3f932c600deb",
|
||||
"408190134ed06556811b1af808ab2d986aff152a28de2c41a2207c0ccc18125ac20f48384de89ea7c80cda1da14e60cc1599943646b4c0082bbcda2d9fa55a13e9df2934edf15eb4fd41f25fa3dd706ab6de522ed351b106321e494e7a27d5f7caf44ec6fadf1122d227eefc0f57aefc140d2c63d07dcbfd65790b1099745ed042cfd1548242076b98e616b76ff0d53db5179df8dd62c06a36a8b9e95a671e2a9b9dd3fb187a31ae5828d218ec5851913e0b52e2532bd4bf9e7b349f32de2b6d5d3cdf9f372d49617b6220c93c05962327e99a0480488443349f0fd54c1860f7c8",
|
||||
"5f9e5c6f38573a85010a9d84d33f29c057003b2645e3ea6f72cbc7af95d197ce6a06b13fea81722853e6991791b8b15091cd066f5ed913592ed3d3af5370d39ba22beeb2a582a414b16824b77e194a094c2afdcc09aa73ce36f4943cca5ae32c5017dc398801dd92a47382d9327c9f6cffd38ca4167cd836f7855fc5ff048d8efba378cdde224905a0425e6b1de061fc951c5e624a5153b008ad41160a710b3ff2081748d5e02deb9f841f4fc6cf4a15153dd4fe874fd447482696283e79ee0e6bc8c1c0409baa5ab02c5209c319e3169b2476149c0c6e541c6197ca46e004eef533",
|
||||
"218c6b3508aec69574f2b5039b30b942b72a8349d05f48ff945bbbe5c8957d5a6199492a6bf54bab821c9377e2edfa4c908384664d2c80112d5e805d66e0a551b941021be17dd20bd825bea9a3b6afb1b8c605805b3bda58750f03ea5c953a698494b425d8980c69f34d1c3f6b5866e8717031152a127215c256e08873c21b0f5cc85875d0f7c94601659150c04cd5fe5d381ba29983a2d94fcd3a65a94c53c7279cd000dddd4253d8cff8d7f6ace10247fe3bc30d63ba4bb54f557b3d22a3924369430d71ab37b701e9500bda70b5a643704858beed4726a889b6c9c91584194c68f1",
|
||||
"dac26aa7273fc25d6e044c79fc2bfa46e59892a42bbca59a86826c91e76ab03e4bd9f7c0b5f08d1931d88b36ea77d94f7ba67cd4f1d3086e529427201119096ae066ae6f170940830ed7900de7bb9d66e09788287403a4ecc93c6da975d2fb08e918840a236c15f5d3a8f7375c2eeebbf6f01a6e7f29ca2b8d42df158414c320777433663c59fdcd1f39ca68e3473db721be7ce8c6dba5fddc024f94fedb286b0477581d451313ca8c737484daf60d67f9b2d56d4bcc271f7e9ae958c7f258efbc74d25753e0516f28282461941bf2dcc7dd8c7df6173b89760cefcac07190243ff863fb",
|
||||
"c46e6512e6797cc7a54254a1b26b2de29aa83d6c4b1ea5a2786fbcec388270625b12635eae39e1fba013f8a65219421bca8b52a8ddfd431cda60299bdf160734d5a7450ec79620058522702174ae451b9bfa7c4a455fbbee3e1d048c7d4bac5131018228f137c8e130440c7059b4f15eaa34ce872a851a16ce86f982df78a00be4d564da2003a450ddee9ab43ea876b8b4b65c84f0b39265fd5456417afb5bc54997c986e66fc222f2123ba5e719c4d6b9a177b188277df384f1125821cf19d5248cef0be183ccdc84ac194506f740ed2188b2689ea4c9236a9e9e3a2fff85b6af4e9b49a3",
|
||||
"1ccd4d278d67b65cf2564ecd4de1b55fe07adc80e1f735fe2f08ea53fd3977323689122c29c798957abaff6aba09bdcbf661d77f4dc8913ab1fe2bef38846166e3834785e7105d746484eff8c656af5d8c7854abc1c62b7fadb65521dc6f793d978bda9838eb3800417d32e8a24d8c8cb1d18a5de6ca79d9e1b0ff9aa25e6218fe944cf18666fecc1e31334b390260dbe0997539e1b02f6366b2aea4f4a21efe04f4b97568fcb39e59919d5ebac6543d5d0f48fc66b923c34aac377dc95c20329b837b6ed5e8d9a3d2089cd0d8f025658006ff41cbdaccca618822ca590ab155253f8bc1c7f5",
|
||||
"9875209588395ee3c9fdd793fd48717cc84c8c3ea622b2ccc4a1be4448e6034b7810569855255031f10be5ffd714b05f9ce01972d712d40abf03d4d0ce175813a7a668f761324996093fc2aa5912f7fc2abdadd8775d2b4d9ad492216293381460ed8f6db3d641d1525f4242c348bbfe504c704f215dc461de51b5c75c1aae967936963848f16c673eca5e78dfd47eb19001d52d1bcf96c98956dad5ddf594a5da757e7ca35f2f69803b784e66ac5a58b75c228b8266ec592505e5d1ca87d81225738855f15bc0914677e81593fd409e77d159f8a908f67788de9eb06c5561547aada96c47c535",
|
||||
"40c90e375e366f3756d89091eb3eed9fe0fbfc5638700af4617d358812bac53124a2205dd6756456787d49cd6a35e302479a0992288f47532e4ea7ab62fc5ad5adc690a5d9a446f7e035ad4641bd8dae83946aee3338ec984ccb5cc633e1409f2531eeffe05532a8b0062ba99454c9aeabf8ecb94db195af7032bfebc22912f49d39330add47ff8fa5720612d697f0b602738930e060a1bb214efc5e292224cf34e29deaea6b1b1ff847e94ecc997325ac38df61db45d82bf0e74a664d2fe085c20b04c39e90d6a170b68d2f1d373f00c731c524456ada73d659aaac9df3191a7a3865083343fc13",
|
||||
"e8800d82e072210ca6d7fa2472028974780b76aad4bcb9ad362422dd05ae3232668251d164daa375a43b26a38cce28dbeb3dee1a4a579f70d0fe7febb29b5ece8aa836e050fb3d188c63aa9c3c0da6c717d86458a6096b5effceb964efdec7035960c09ccd10dea3c5f1c7f9f478d5887ebbe2e15c5ff85dbacbc444bb951c4eec7abecb89ed80187e409e2972ffe1a5f01562af109f2cf09471cf72cf83a3bb8f4e2ef38ed0e326b698296394e5b2718a5000c01425708e8ad0461e62462d8819c2377f13ab1be2c7c9f33dc06fe23cad27b87569f2ce2e56e4b2c60c7b1b3d370841d89ebdc1f192",
|
||||
"796d6d1447d5b7e8c55cd8b2f8b7010db39f27565f907e3fc0e464ea2d4bb52b37f10e7c6dcfc59231b9cdee12c32aeb4adbc42b86e86eb6defb5b69e6ca75e1f4d0dae3e124e5a1b8b6697f7e10b0403f1f0a5ff848eef3752837a9ba17780f16a9a709188a8d5b89a2fa74adb2e651163b1c2b3d261e225c9158dcd9eb7ac3d6704cee290cdff6bcb3cb90cee030aa0d19d4693655c3c30ac6fc06d2ae37787c47126d57ed9a6bef5f8a6c56859aefc08755739a95aac57a4dd916a92ba9f3afbf969df8085949615033365c751a9a3e1a18cee98a69d22e64009bebf8307169b6c61de0617ecfafdf",
|
||||
"4f9057183566153cf337b07c3f5556006de54c56b2a1e5326c07aaeabd1886ec6f1641358925db232b2f0dbf75229c796a7395b2f934c1f99090bec1123f3c841b1cb3c5b1ec42ed5408f2940f0c48a9470b852c46d6557853d459cecd2c32bbcd8ee21fa11e385eef0857cba4d8545a61b52a484cdd779db4739fbc7aa9860dcabe0488b98fa0b60c3f7d6153db279000a52ffb573dab37d2ab1896a90e5deb7ac6bbe56239085c325d83a917dc6e8a448425b718c2356b9f3066163555ec444f372e184e02c8c4c69b1c1c2ae2b51e45b98f73d933d18750968945ca85d6bbb22014b4c4015262e3c40d",
|
||||
"79dcca7d8b81a61359e4aece21f3df7b99518ce70bd2f57a18bab5e7114af2add0a0cea7f319d69f231f060e0a539d9a23fb3e95451ce8c6340cfb09edf931df84203a39226dd9eb278f11b691ef612585b973daab373e65d11325898badf6732100371fd759960fa8fec373268421d28bffdb9b12a430b92fe4b07566ca0c89e616e49f8fc75ccd9cdc66db820d7c02e109aa5ed86b89770262918a518f90a2292f6b68d68ae03992e4259a17a23c84ec2a417f082b5abf3a26e44d2278ecb8ba9456965303a75f25394d1aaf5544590e74b14d8a4cc4050be2b0ebcfe4d2db6b12a02c68a3bcdda70301f3",
|
||||
"848755dc31e25e9a42f9ec12d847d19f292c14c162c9aba49e972cb123b58b8e57bb263a923929833373858594ff52dbc298dbbc078599194e4c07b0e5fc1e10808bbacdb6e93c72b333685cf961f28eb0d5a395c63266b01f130d25db384b356e5da6d01042fc2359581b89c63b3bb2d1ce897fbc9e83fe85d9666cb60e6a8c657f70caad5387b8a045bf91095606802c8424ea8ac52ef29386dc46183378a5fcb2cb927428b8c070f1c42aafd3bc70ca25437807696a46873cfeb7b80ba2ebc3c4272443d445e46343a1465253a9eebd532a0d1d2c18264b91ff45159f245404ae9335f2af55c802772426b4",
|
||||
"ecaa6e999ef355a0768730edb835db411829a3764f79d764bb5682af6d00f51b313e017b83fffe2e332cd4a3de0a81d6a52084d5748346a1f81eb9b183ff6d93d05edc00e938d001c90872dfe234e8dd085f639af168af4a07e18f1c56ca6c7c1addffc4a70eb4660666dda0321636c3f83479ad3b64e23d749620413a2ecdcc52ad4e6e63f2b817ce99c15b5d2da3792721d7158297cce65e0c04fe810d7e2434b969e4c7892b3840623e153576356e9a696fd9e7a801c25de621a7849da3f99158d3d09bf039f43c510c8ffb00fa3e9a3c12d2c8062dd25b8dabe53d8581e30427e81c3dfc2d455352487e1255",
|
||||
"23a3fe80e3636313fdf922a1359514d9f31775e1adf24285e8001c04dbce866df055edf25b506e18953492a173ba5aa0c1ec758123406a97025ba9b6b7a97eb14734424d1a7841ec0eaeba0051d6e9734263bea1af9895a3b8c83d8c854da2ae7832bdd7c285b73f8113c3821cced38b3656b4e6369a9f8327cd368f04128f1d78b6b4260f55995277feffa15e34532cd0306c1f47354667c17018ee012a791af2dbbc7afc92c388008c601740cccbbe66f1eb06ea657e9d478066c2bd2093ab62cd94abadc002722f50968e8acf361658fc64f50685a5b1b004888b3b4f64a4ddb67bec7e4ac64c9ee8deeda896b9",
|
||||
"758f3567cd992228386a1c01930f7c52a9dcce28fdc1aaa54b0fed97d9a54f1df805f31bac12d559e90a2063cd7df8311a148f6904f78c5440f75e49877c0c0855d59c7f7ee52837e6ef3e54a568a7b38a0d5b896e298c8e46a56d24d8cabda8aeff85a622a3e7c87483ba921f34156defd185f608e2241224286e38121a162c2ba7604f68484717196f6628861a948180e8f06c6cc1ec66d032cf8d16da039cd74277cde31e535bc1692a44046e16881c954af3cd91dc49b443a3680e4bc42a954a46ebd1368b1398edd7580f935514b15c7fbfa9b40048a35122283af731f5e460aa85b66e65f49a9d158699bd2870",
|
||||
"fe511e86971cea2b6af91b2afa898d9b067fa71780790bb409189f5debe719f405e16acf7c4306a6e6ac5cd535290efe088943b9e6c5d25bfc508023c1b105d20d57252fee8cdbddb4d34a6ec2f72e8d55be55afcafd2e922ab8c31888bec4e816d04f0b2cd23df6e04720969c5152b3563c6da37e4608554cc7b8715bc10aba6a2e3b6fbcd35408df0dd73a9076bfad32b741fcdb0edfb563b3f753508b9b26f0a91673255f9bcda2b9a120f6bfa0632b6551ca517d846a747b66ebda1b2170891ece94c19ce8bf682cc94afdf0053fba4e4f0530935c07cdd6f879c999a8c4328ef6d3e0a37974a230ada83910604337",
|
||||
"a6024f5b959698c0de45f4f29e1803f99dc8112989c536e5a1337e281bc856ff721e986de183d7b0ea9eb61166830ae5d6d6bc857dc833ff189b52889b8e2bd3f35b4937624d9b36dc5f19db44f0772508029784c7dac9568d28609058bc437e2f79f95b12307d8a8fb042d7fd6ee910a9e8df609ede3283f958ba918a9925a0b1d0f9f9f232062315f28a52cbd60e71c09d83e0f6600f508f0ae8ad7642c080ffc618fcd2314e26f67f1529342569f6df37017f7e3b2dac32ad88d56d175ab22205ee7e3ee94720d76933a21132e110fefbb0689a3adbaa4c685f43652136d09b3a359b5c671e38f11915cb5612db2ae294",
|
||||
"af6de0e227bd78494acb559ddf34d8a7d55a03912384831be21c38376f39cda8a864aff7a48aed758f6bdf777779a669068a75ce82a06f6b3325c855ed83daf5513a078a61f7dc6c1622a633367e5f3a33e765c8ec5d8d54f48494006fdbf8922063e5340013e312871b7f8f8e5ea439c0d4cb78e2f19dd11f010729b692c65dd0d347f0ce53de9d849224666ea2f6487f1c6f953e8f9dbfd3d6de291c3e9d045e633cfd83c89d2f2327d0b2f31f72ac1604a3db1febc5f22cad08153278047210cc2894582c251a014c652e3951593e70e52a5d7451be8924b64f85c8247dab6268d24710b39fc1c07b4ac829fbda34ed79b5",
|
||||
"d7314e8b1ff82100b8f5870da62b61c31ab37ace9e6a7b6f7d294571523783c1fdedcbc00dd487dd6f848c34aab493507d07071b5eb59d1a2346068c7f356755fbde3d2cab67514f8c3a12d6ff9f96a977a9ac9263491bd33122a904da5386b943d35a6ba383932df07f259b6b45f69e9b27b4ca124fb3ae143d709853eed86690bc2754d5f8865c355a44b5279d8eb31cdc00f7407fb5f5b34edc57fc7ace943565da2222dc80632ccf42f2f125ceb19714ea964c2e50603c9f8960c3f27c2ed0e18a559931c4352bd7422109a28c5e145003f55c9b7c664fdc985168868950396eaf6fefc7b73d815c1aca721d7c67da632925",
|
||||
"2928b55c0e4d0f5cb4b60af59e9a702e3d616a8cf427c8bb03981fb8c29026d8f7d89161f36c11654f9a5e8ccb703595a58d671ecdc22c6a784abe363158682be4643002a7da5c9d268a30ea9a8d4cc24f562ab59f55c2b43af7dbcecc7e5ebe7494e82d74145a1e7d442125eb0431c5ea0939b27afa47f8ca97849f341f707660c7fbe49b7a0712fbcb6f7562ae2961425f27c7779c7534ecdeb8047ff3cb89a25159f3e1cefe42f9ef16426241f2c4d62c11d7ac43c4500dfcd184436bb4ef33260366f875230f26d81613c334dbda4736ba9d1d2966502914ec01bbe72d885606ec11da7a2cb01b29d35eebedbb0ecc73ed6c35",
|
||||
"fd993f50e8a68c7b2c7f87511ce65b93c0aa94dcbdf2c9cca93816f0f3b2ab34c62c586fc507b4900a34cf9d0517e0fe10a89d154c5419c1f5e38de00e8834fe3dc1032abdeb10729a81655a69a12856a78ca6e12110580de879b086fd6608726541cfa9616326bdd36064bc0d1e5f9c93b41278bff6a13b2494b81e238c0c45aea1b07d855e8f3fe1478e373bd9d3957cf8a5e5b9003386793d994c7c575cff2322e2428cbbaa4f47560316ae3354a7478842ff7cc5dcbacb6e871e72b36f06d63a9aaeb9044cfb7974afdc238a5816f537dcf33ee40b4e1a5eb3cff2402b46d548264e133008d284f11b7e4e450bc3c5ff9f79b9c4",
|
||||
"8df21892f5fc303b0de4adef1970186db6fe71bb3ea3094922e13afcfabf1d0be009f36d6f6310c5f9fda51f1a946507a055b645c296370440e5e83d8e906a2fb51f2b42de8856a81a4f28a73a8825c68ea08e5e366730bce8047011cb7d6d9be8c6f4211308fad21856284d5bc47d199988e0abf5badf8693ceeed0a2d98e8ae94b7775a42925edb1f697ffbd8e806af23145054a85e071819cca4cd48875290ca65e5ee72a9a54ff9f19c10ef4adaf8d04c9a9afcc73853fc128bbebc61f78702787c966ca6e1b1a0e4dab646acdfcd3c6bf3e5cfbec5ebe3e06c8abaa1de56e48421d87c46b5c78030afcafd91f27e7d7c85eb4872b",
|
||||
"48ec6ec520f8e593d7b3f653eb15553de246723b81a6d0c3221aaa42a37420fba98a23796338dff5f845dce6d5a449be5ecc1887356619270461087e08d05fb60433a83d7bd00c002b09ea210b428965124b9b27d9105a71c826c1a2491cfd60e4cfa86c2da0c7100a8dc1c3f2f94b280d54e01e043acf0e966200d9fa8a41daf3b9382820786c75cadbb8841a1b2be5b6cbeb64878e4a231ae063a99b4e2308960ef0c8e2a16bb3545cc43bdf171493fb89a84f47e7973dc60cf75aeeca71e0a7ebe17d161d4fb9fe009941cc438f16a5bae6c99fcad08cac486eb2a48060b023d8730bf1d82fe60a2f036e6f52a5bff95f43bbe088933f",
|
||||
"f4d84ed3e564c102600a795eaa9b1eaf4ad12f1a4deca1d042a0a2750ddf6201db03073d8bf553cb9dde48a1b0083827a609f7242b86584cc180964ae794b12ce55661e00e36a6ba4dbc389e6a5a85f1b45df9af7ead1b0a54db56e68639b9d438a91504e82c35d40c7bc7e048a53ac0b04accd0dadf4ac9884b0ca0e3cb5ba4336e3581be4c4760a553823ffa283a1120d4e145af56a59f2533903650f0b9e9ad9fe2e8a3c3c3dd03a1fcb709032c8835324839c735b0c051d0cbd8b5d867617c11023432e4bd275d3d0eb98a0b6cf58071a5b712922f2bc751ac7c2588c447444cde2f37a8ea5ec126425bf517e0d17c9e2999f52fee14b3",
|
||||
"2ccea21bac9c2b70d3923309cbf2d7cb7abd1fcc8b8b002688870a80029c62397350c3c898194e5deea360bb963d26d485cb7963f8167586976ec0556950b2e86135f4a2800991ce8473bfd44a3c5e937a48b5e355ba5141bccf2131a83988d9d2a9e8e7635a956105b3512c05ef708139ced51d7a4e204c12d8a49a21e8dc6de2629a2fd092326885d9f218745fe09f6d91fb6afce250a30a63689534b6be1f26899ffa3767d835cf586aa47776700f94241bc999b1e3deefe188f37ff734f5f16ee6a00914323dc7b8a143c9137cdcc5cd08ae9566f04bb2941532674c97dff6ffa5ce3405ef8e5d27ec403114253dd6394c0167d72a0044c5",
|
||||
"2b681c6398aee63bf862770341648bbcd31d7de7903c5903fe3d9469311320bb24d914f2af0cdca199c97214c7c679dc32a2800ba484a03c010ea6be3bb9f2c87e30a98b606050b8a3f297f12b8f92caaeceb3e844652115934874e0a1ab093a73d759b53f6a6c3096940dd22c2bb96ce6820a7b9c6d71a208de9892aa6a7209b0fff56a0cafea52b952cdd6f5752cff3309d448800b4e4c878aa595595b56b12b83fcd6ca89520c7da664e449d7b4438fc455888aad5de0fad9a06eed14afd3513b5ebbffe01775549b701181bd26370764f56eba52fdb24286ad1ac0f5418a7c429f7dfc7f3168437fa8eed7a2ed7c723a485e4c3ed14dea2e07",
|
||||
"aadfd505a89f4aade2c3018258a7e039401b1fc6a7f3d87910dddbb880d372ec8a13c70d92245de5b8e5f9a285c33b99dc82fa2b22decee72b93a72211656ad7a52696c8e570f78be28c0e427a371dafde856e8d5ed24f83b0660b51e7fac05d93a8666dfde6def59af863f80f3e5f6801182c87422203df390dcb736b8f830052a8832eeeb0b4e27e732aaf793d166b5a3ec7745aeef3766937c2b75a276bddd145f6010c29d035e343e267cb2d828436876ec3a7ebe3b6347d4172f7a99d6821ce152e039e53deb33340b324c7f068ffb94b3cde35a8eaa12d15c3806a7ad0acec3e8c7078c1d32a28fd3eec9f32cb86e4c22166ff69e83785e851",
|
||||
"1605b8cce529a9d6262fd4390d9e4ae5e14e0adc0ec89b028ef68dd0f373ea259aaa96f2967091dd0874c0105385e9e6da9ca68297c31afa44ef834535fb302ce5b4e49edacbbdf359fe1228a8172495b3e57014c27edd58b685110980056c50c398a64f4923f2d720b4df16d75cb36b4233660694182099c35028a972519c24764fc94e18e582b24deb3491535fc06b83837c7958522800e822201d694af0bd0aa3834e17d4b1ba36f470905ae5f8bbeeb6c4c8604d8af02baa347b07086d6989867ddd5e8e8ed7740c3469bfa2810519c55c6add1332c4c54ee9097961d6741cb12a09713a0d07645f784f42f5ad94b48b836b34263130b0483f15e3",
|
||||
"ff9c6125b2f60bfd6c2427b279df070e430075096647599bdc68c531152c58e13858b82385d78c856092d6c74106e87ccf51ac7e673936332d9b223444eaa0e762ee258d8a733d3a515ec68ed73285e5ca183ae3278b4820b0ab2797feb1e7d8cc864df585dfb5ebe02a993325a9ad5e2d7d49d3132cf66013898351d044e0fe908ccdfeeebf651983601e3673a1f92d36510c0cc19b2e75856db8e4a41f92a51efa66d6cc22e414944c2c34a5a89ccde0be76f51410824e330d8e7c613194338c93732e8aea651fca18bcf1ac1824340c5553aff1e58d4ab8d7c8842b4712021e517cd6c140f6743c69c7bee05b10a8f24050a8caa4f96d1664909c5a06",
|
||||
"6e85c2f8e1fdc3aaeb969da1258cb504bbf0070cd03d23b3fb5ee08feea5ee2e0ee1c71a5d0f4f701b351f4e4b4d74cb1e2ae6184814f77b62d2f08134b7236ebf6b67d8a6c9f01b4248b30667c555f5d8646dbfe291151b23c9c9857e33a4d5c847be29a5ee7b402e03bac02d1a4319acc0dd8f25e9c7a266f5e5c896cc11b5b238df96a0963ae806cb277abc515c298a3e61a3036b177acf87a56ca4478c4c6d0d468913de602ec891318bbaf52c97a77c35c5b7d164816cf24e4c4b0b5f45853882f716d61eb947a45ce2efa78f1c70a918512af1ad536cbe6148083385b34e207f5f690d7a954021e4b5f4258a385fd8a87809a481f34202af4caccb82",
|
||||
"1e9b2c454e9de3a2d723d850331037dbf54133dbe27488ff757dd255833a27d8eb8a128ad12d0978b6884e25737086a704fb289aaaccf930d5b582ab4df1f55f0c429b6875edec3fe45464fa74164be056a55e243c4222c586bec5b18f39036aa903d98180f24f83d09a454dfa1e03a60e6a3ba4613e99c35f874d790174ee48a557f4f021ade4d1b278d7997ef094569b37b3db0505951e9ee8400adaea275c6db51b325ee730c69df97745b556ae41cd98741e28aa3a49544541eeb3da1b1e8fa4e8e9100d66dd0c7f5e2c271b1ecc077de79c462b9fe4c273543ecd82a5bea63c5acc01eca5fb780c7d7c8c9fe208ae8bd50cad1769693d92c6c8649d20d8",
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blake2b
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// XOF defines the interface to hash functions that
|
||||
// support arbitrary-length output.
|
||||
type XOF interface {
|
||||
// Write absorbs more data into the hash's state. It panics if called
|
||||
// after Read.
|
||||
io.Writer
|
||||
|
||||
// Read reads more output from the hash. It returns io.EOF if the limit
|
||||
// has been reached.
|
||||
io.Reader
|
||||
|
||||
// Clone returns a copy of the XOF in its current state.
|
||||
Clone() XOF
|
||||
|
||||
// Reset resets the XOF to its initial state.
|
||||
Reset()
|
||||
}
|
||||
|
||||
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
|
||||
// the the length of the output is not known in advance.
|
||||
const OutputLengthUnknown = 0
|
||||
|
||||
// magicUnknownOutputLength is a magic value for the output size that indicates
|
||||
// an unknown number of output bytes.
|
||||
const magicUnknownOutputLength = (1 << 32) - 1
|
||||
|
||||
// maxOutputLength is the absolute maximum number of bytes to produce when the
|
||||
// number of output bytes is unknown.
|
||||
const maxOutputLength = (1 << 32) * 64
|
||||
|
||||
// NewXOF creates a new variable-output-length hash. The hash either produce a
|
||||
// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes
|
||||
// (size == OutputLengthUnknown). In the latter case, an absolute limit of
|
||||
// 256GiB applies.
|
||||
//
|
||||
// A non-nil key turns the hash into a MAC. The key must between
|
||||
// zero and 32 bytes long.
|
||||
func NewXOF(size uint32, key []byte) (XOF, error) {
|
||||
if len(key) > Size {
|
||||
return nil, errKeySize
|
||||
}
|
||||
if size == magicUnknownOutputLength {
|
||||
// 2^32-1 indicates an unknown number of bytes and thus isn't a
|
||||
// valid length.
|
||||
return nil, errors.New("blake2b: XOF length too large")
|
||||
}
|
||||
if size == OutputLengthUnknown {
|
||||
size = magicUnknownOutputLength
|
||||
}
|
||||
x := &xof{
|
||||
d: digest{
|
||||
size: Size,
|
||||
keyLen: len(key),
|
||||
},
|
||||
length: size,
|
||||
}
|
||||
copy(x.d.key[:], key)
|
||||
x.Reset()
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type xof struct {
|
||||
d digest
|
||||
length uint32
|
||||
remaining uint64
|
||||
cfg, root, block [Size]byte
|
||||
offset int
|
||||
nodeOffset uint32
|
||||
readMode bool
|
||||
}
|
||||
|
||||
func (x *xof) Write(p []byte) (n int, err error) {
|
||||
if x.readMode {
|
||||
panic("blake2b: write to XOF after read")
|
||||
}
|
||||
return x.d.Write(p)
|
||||
}
|
||||
|
||||
func (x *xof) Clone() XOF {
|
||||
clone := *x
|
||||
return &clone
|
||||
}
|
||||
|
||||
func (x *xof) Reset() {
|
||||
x.cfg[0] = byte(Size)
|
||||
binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
|
||||
binary.LittleEndian.PutUint32(x.cfg[12:], x.length) // XOF length
|
||||
x.cfg[17] = byte(Size) // inner hash size
|
||||
|
||||
x.d.Reset()
|
||||
x.d.h[1] ^= uint64(x.length) << 32
|
||||
|
||||
x.remaining = uint64(x.length)
|
||||
if x.remaining == magicUnknownOutputLength {
|
||||
x.remaining = maxOutputLength
|
||||
}
|
||||
x.offset, x.nodeOffset = 0, 0
|
||||
x.readMode = false
|
||||
}
|
||||
|
||||
func (x *xof) Read(p []byte) (n int, err error) {
|
||||
if !x.readMode {
|
||||
x.d.finalize(&x.root)
|
||||
x.readMode = true
|
||||
}
|
||||
|
||||
if x.remaining == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
n = len(p)
|
||||
if uint64(n) > x.remaining {
|
||||
n = int(x.remaining)
|
||||
p = p[:n]
|
||||
}
|
||||
|
||||
if x.offset > 0 {
|
||||
blockRemaining := Size - x.offset
|
||||
if n < blockRemaining {
|
||||
x.offset += copy(p, x.block[x.offset:])
|
||||
x.remaining -= uint64(n)
|
||||
return
|
||||
}
|
||||
copy(p, x.block[x.offset:])
|
||||
p = p[blockRemaining:]
|
||||
x.offset = 0
|
||||
x.remaining -= uint64(blockRemaining)
|
||||
}
|
||||
|
||||
for len(p) >= Size {
|
||||
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
|
||||
x.nodeOffset++
|
||||
|
||||
x.d.initConfig(&x.cfg)
|
||||
x.d.Write(x.root[:])
|
||||
x.d.finalize(&x.block)
|
||||
|
||||
copy(p, x.block[:])
|
||||
p = p[Size:]
|
||||
x.remaining -= uint64(Size)
|
||||
}
|
||||
|
||||
if todo := len(p); todo > 0 {
|
||||
if x.remaining < uint64(Size) {
|
||||
x.cfg[0] = byte(x.remaining)
|
||||
}
|
||||
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
|
||||
x.nodeOffset++
|
||||
|
||||
x.d.initConfig(&x.cfg)
|
||||
x.d.Write(x.root[:])
|
||||
x.d.finalize(&x.block)
|
||||
|
||||
x.offset = copy(p, x.block[:todo])
|
||||
x.remaining -= uint64(todo)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest) initConfig(cfg *[Size]byte) {
|
||||
d.offset, d.c[0], d.c[1] = 0, 0, 0
|
||||
for i := range d.h {
|
||||
d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.9
|
||||
|
||||
package blake2b
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
)
|
||||
|
||||
func init() {
|
||||
newHash256 := func() hash.Hash {
|
||||
h, _ := New256(nil)
|
||||
return h
|
||||
}
|
||||
newHash384 := func() hash.Hash {
|
||||
h, _ := New384(nil)
|
||||
return h
|
||||
}
|
||||
|
||||
newHash512 := func() hash.Hash {
|
||||
h, _ := New512(nil)
|
||||
return h
|
||||
}
|
||||
|
||||
crypto.RegisterHash(crypto.BLAKE2b_256, newHash256)
|
||||
crypto.RegisterHash(crypto.BLAKE2b_384, newHash384)
|
||||
crypto.RegisterHash(crypto.BLAKE2b_512, newHash512)
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
// 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 blake2s implements the BLAKE2s hash algorithm defined by RFC 7693
|
||||
// and the extendable output function (XOF) BLAKE2Xs.
|
||||
//
|
||||
// For a detailed specification of BLAKE2s see https://blake2.net/blake2.pdf
|
||||
// and for BLAKE2Xs see https://blake2.net/blake2x.pdf
|
||||
//
|
||||
// If you aren't sure which function you need, use BLAKE2s (Sum256 or New256).
|
||||
// If you need a secret-key MAC (message authentication code), use the New256
|
||||
// function with a non-nil key.
|
||||
//
|
||||
// BLAKE2X is a construction to compute hash values larger than 32 bytes. It
|
||||
// can produce hash values between 0 and 65535 bytes.
|
||||
package blake2s // import "golang.org/x/crypto/blake2s"
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"hash"
|
||||
)
|
||||
|
||||
const (
|
||||
// The blocksize of BLAKE2s in bytes.
|
||||
BlockSize = 64
|
||||
|
||||
// The hash size of BLAKE2s-256 in bytes.
|
||||
Size = 32
|
||||
|
||||
// The hash size of BLAKE2s-128 in bytes.
|
||||
Size128 = 16
|
||||
)
|
||||
|
||||
var errKeySize = errors.New("blake2s: invalid key size")
|
||||
|
||||
var iv = [8]uint32{
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
||||
}
|
||||
|
||||
// Sum256 returns the BLAKE2s-256 checksum of the data.
|
||||
func Sum256(data []byte) [Size]byte {
|
||||
var sum [Size]byte
|
||||
checkSum(&sum, Size, data)
|
||||
return sum
|
||||
}
|
||||
|
||||
// New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil
|
||||
// key turns the hash into a MAC. The key must between zero and 32 bytes long.
|
||||
func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
|
||||
|
||||
// New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
|
||||
// non-empty key. Note that a 128-bit digest is too small to be secure as a
|
||||
// cryptographic hash and should only be used as a MAC, thus the key argument
|
||||
// is not optional.
|
||||
func New128(key []byte) (hash.Hash, error) {
|
||||
if len(key) == 0 {
|
||||
return nil, errors.New("blake2s: a key is required for a 128-bit hash")
|
||||
}
|
||||
return newDigest(Size128, key)
|
||||
}
|
||||
|
||||
func newDigest(hashSize int, key []byte) (*digest, error) {
|
||||
if len(key) > Size {
|
||||
return nil, errKeySize
|
||||
}
|
||||
d := &digest{
|
||||
size: hashSize,
|
||||
keyLen: len(key),
|
||||
}
|
||||
copy(d.key[:], key)
|
||||
d.Reset()
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func checkSum(sum *[Size]byte, hashSize int, data []byte) {
|
||||
var (
|
||||
h [8]uint32
|
||||
c [2]uint32
|
||||
)
|
||||
|
||||
h = iv
|
||||
h[0] ^= uint32(hashSize) | (1 << 16) | (1 << 24)
|
||||
|
||||
if length := len(data); length > BlockSize {
|
||||
n := length &^ (BlockSize - 1)
|
||||
if length == n {
|
||||
n -= BlockSize
|
||||
}
|
||||
hashBlocks(&h, &c, 0, data[:n])
|
||||
data = data[n:]
|
||||
}
|
||||
|
||||
var block [BlockSize]byte
|
||||
offset := copy(block[:], data)
|
||||
remaining := uint32(BlockSize - offset)
|
||||
|
||||
if c[0] < remaining {
|
||||
c[1]--
|
||||
}
|
||||
c[0] -= remaining
|
||||
|
||||
hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
|
||||
|
||||
for i, v := range h {
|
||||
binary.LittleEndian.PutUint32(sum[4*i:], v)
|
||||
}
|
||||
}
|
||||
|
||||
type digest struct {
|
||||
h [8]uint32
|
||||
c [2]uint32
|
||||
size int
|
||||
block [BlockSize]byte
|
||||
offset int
|
||||
|
||||
key [BlockSize]byte
|
||||
keyLen int
|
||||
}
|
||||
|
||||
func (d *digest) BlockSize() int { return BlockSize }
|
||||
|
||||
func (d *digest) Size() int { return d.size }
|
||||
|
||||
func (d *digest) Reset() {
|
||||
d.h = iv
|
||||
d.h[0] ^= uint32(d.size) | (uint32(d.keyLen) << 8) | (1 << 16) | (1 << 24)
|
||||
d.offset, d.c[0], d.c[1] = 0, 0, 0
|
||||
if d.keyLen > 0 {
|
||||
d.block = d.key
|
||||
d.offset = BlockSize
|
||||
}
|
||||
}
|
||||
|
||||
func (d *digest) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
|
||||
if d.offset > 0 {
|
||||
remaining := BlockSize - d.offset
|
||||
if n <= remaining {
|
||||
d.offset += copy(d.block[d.offset:], p)
|
||||
return
|
||||
}
|
||||
copy(d.block[d.offset:], p[:remaining])
|
||||
hashBlocks(&d.h, &d.c, 0, d.block[:])
|
||||
d.offset = 0
|
||||
p = p[remaining:]
|
||||
}
|
||||
|
||||
if length := len(p); length > BlockSize {
|
||||
nn := length &^ (BlockSize - 1)
|
||||
if length == nn {
|
||||
nn -= BlockSize
|
||||
}
|
||||
hashBlocks(&d.h, &d.c, 0, p[:nn])
|
||||
p = p[nn:]
|
||||
}
|
||||
|
||||
d.offset += copy(d.block[:], p)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest) Sum(sum []byte) []byte {
|
||||
var hash [Size]byte
|
||||
d.finalize(&hash)
|
||||
return append(sum, hash[:d.size]...)
|
||||
}
|
||||
|
||||
func (d *digest) finalize(hash *[Size]byte) {
|
||||
var block [BlockSize]byte
|
||||
h := d.h
|
||||
c := d.c
|
||||
|
||||
copy(block[:], d.block[:d.offset])
|
||||
remaining := uint32(BlockSize - d.offset)
|
||||
if c[0] < remaining {
|
||||
c[1]--
|
||||
}
|
||||
c[0] -= remaining
|
||||
|
||||
hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
|
||||
for i, v := range h {
|
||||
binary.LittleEndian.PutUint32(hash[4*i:], v)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// 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.
|
||||
|
||||
// +build 386,!gccgo,!appengine
|
||||
|
||||
package blake2s
|
||||
|
||||
var (
|
||||
useSSE4 = false
|
||||
useSSSE3 = supportSSSE3()
|
||||
useSSE2 = supportSSE2()
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func supportSSE2() bool
|
||||
|
||||
//go:noescape
|
||||
func supportSSSE3() bool
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
|
||||
if useSSSE3 {
|
||||
hashBlocksSSSE3(h, c, flag, blocks)
|
||||
} else if useSSE2 {
|
||||
hashBlocksSSE2(h, c, flag, blocks)
|
||||
} else {
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,460 @@
|
|||
// 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.
|
||||
|
||||
// +build 386,!gccgo,!appengine
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
DATA iv0<>+0x00(SB)/4, $0x6a09e667
|
||||
DATA iv0<>+0x04(SB)/4, $0xbb67ae85
|
||||
DATA iv0<>+0x08(SB)/4, $0x3c6ef372
|
||||
DATA iv0<>+0x0c(SB)/4, $0xa54ff53a
|
||||
GLOBL iv0<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA iv1<>+0x00(SB)/4, $0x510e527f
|
||||
DATA iv1<>+0x04(SB)/4, $0x9b05688c
|
||||
DATA iv1<>+0x08(SB)/4, $0x1f83d9ab
|
||||
DATA iv1<>+0x0c(SB)/4, $0x5be0cd19
|
||||
GLOBL iv1<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA rol16<>+0x00(SB)/8, $0x0504070601000302
|
||||
DATA rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A
|
||||
GLOBL rol16<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA rol8<>+0x00(SB)/8, $0x0407060500030201
|
||||
DATA rol8<>+0x08(SB)/8, $0x0C0F0E0D080B0A09
|
||||
GLOBL rol8<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA counter<>+0x00(SB)/8, $0x40
|
||||
DATA counter<>+0x08(SB)/8, $0x0
|
||||
GLOBL counter<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
#define ROTL_SSE2(n, t, v) \
|
||||
MOVO v, t; \
|
||||
PSLLL $n, t; \
|
||||
PSRLL $(32-n), v; \
|
||||
PXOR t, v
|
||||
|
||||
#define ROTL_SSSE3(c, v) \
|
||||
PSHUFB c, v
|
||||
|
||||
#define ROUND_SSE2(v0, v1, v2, v3, m0, m1, m2, m3, t) \
|
||||
PADDL m0, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSE2(16, t, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(20, t, v1); \
|
||||
PADDL m1, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSE2(24, t, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(25, t, v1); \
|
||||
PSHUFL $0x39, v1, v1; \
|
||||
PSHUFL $0x4E, v2, v2; \
|
||||
PSHUFL $0x93, v3, v3; \
|
||||
PADDL m2, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSE2(16, t, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(20, t, v1); \
|
||||
PADDL m3, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSE2(24, t, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(25, t, v1); \
|
||||
PSHUFL $0x39, v3, v3; \
|
||||
PSHUFL $0x4E, v2, v2; \
|
||||
PSHUFL $0x93, v1, v1
|
||||
|
||||
#define ROUND_SSSE3(v0, v1, v2, v3, m0, m1, m2, m3, t, c16, c8) \
|
||||
PADDL m0, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSSE3(c16, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(20, t, v1); \
|
||||
PADDL m1, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSSE3(c8, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(25, t, v1); \
|
||||
PSHUFL $0x39, v1, v1; \
|
||||
PSHUFL $0x4E, v2, v2; \
|
||||
PSHUFL $0x93, v3, v3; \
|
||||
PADDL m2, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSSE3(c16, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(20, t, v1); \
|
||||
PADDL m3, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSSE3(c8, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(25, t, v1); \
|
||||
PSHUFL $0x39, v3, v3; \
|
||||
PSHUFL $0x4E, v2, v2; \
|
||||
PSHUFL $0x93, v1, v1
|
||||
|
||||
#define PRECOMPUTE(dst, off, src, t) \
|
||||
MOVL 0*4(src), t; \
|
||||
MOVL t, 0*4+off+0(dst); \
|
||||
MOVL t, 9*4+off+64(dst); \
|
||||
MOVL t, 5*4+off+128(dst); \
|
||||
MOVL t, 14*4+off+192(dst); \
|
||||
MOVL t, 4*4+off+256(dst); \
|
||||
MOVL t, 2*4+off+320(dst); \
|
||||
MOVL t, 8*4+off+384(dst); \
|
||||
MOVL t, 12*4+off+448(dst); \
|
||||
MOVL t, 3*4+off+512(dst); \
|
||||
MOVL t, 15*4+off+576(dst); \
|
||||
MOVL 1*4(src), t; \
|
||||
MOVL t, 4*4+off+0(dst); \
|
||||
MOVL t, 8*4+off+64(dst); \
|
||||
MOVL t, 14*4+off+128(dst); \
|
||||
MOVL t, 5*4+off+192(dst); \
|
||||
MOVL t, 12*4+off+256(dst); \
|
||||
MOVL t, 11*4+off+320(dst); \
|
||||
MOVL t, 1*4+off+384(dst); \
|
||||
MOVL t, 6*4+off+448(dst); \
|
||||
MOVL t, 10*4+off+512(dst); \
|
||||
MOVL t, 3*4+off+576(dst); \
|
||||
MOVL 2*4(src), t; \
|
||||
MOVL t, 1*4+off+0(dst); \
|
||||
MOVL t, 13*4+off+64(dst); \
|
||||
MOVL t, 6*4+off+128(dst); \
|
||||
MOVL t, 8*4+off+192(dst); \
|
||||
MOVL t, 2*4+off+256(dst); \
|
||||
MOVL t, 0*4+off+320(dst); \
|
||||
MOVL t, 14*4+off+384(dst); \
|
||||
MOVL t, 11*4+off+448(dst); \
|
||||
MOVL t, 12*4+off+512(dst); \
|
||||
MOVL t, 4*4+off+576(dst); \
|
||||
MOVL 3*4(src), t; \
|
||||
MOVL t, 5*4+off+0(dst); \
|
||||
MOVL t, 15*4+off+64(dst); \
|
||||
MOVL t, 9*4+off+128(dst); \
|
||||
MOVL t, 1*4+off+192(dst); \
|
||||
MOVL t, 11*4+off+256(dst); \
|
||||
MOVL t, 7*4+off+320(dst); \
|
||||
MOVL t, 13*4+off+384(dst); \
|
||||
MOVL t, 3*4+off+448(dst); \
|
||||
MOVL t, 6*4+off+512(dst); \
|
||||
MOVL t, 10*4+off+576(dst); \
|
||||
MOVL 4*4(src), t; \
|
||||
MOVL t, 2*4+off+0(dst); \
|
||||
MOVL t, 1*4+off+64(dst); \
|
||||
MOVL t, 15*4+off+128(dst); \
|
||||
MOVL t, 10*4+off+192(dst); \
|
||||
MOVL t, 6*4+off+256(dst); \
|
||||
MOVL t, 8*4+off+320(dst); \
|
||||
MOVL t, 3*4+off+384(dst); \
|
||||
MOVL t, 13*4+off+448(dst); \
|
||||
MOVL t, 14*4+off+512(dst); \
|
||||
MOVL t, 5*4+off+576(dst); \
|
||||
MOVL 5*4(src), t; \
|
||||
MOVL t, 6*4+off+0(dst); \
|
||||
MOVL t, 11*4+off+64(dst); \
|
||||
MOVL t, 2*4+off+128(dst); \
|
||||
MOVL t, 9*4+off+192(dst); \
|
||||
MOVL t, 1*4+off+256(dst); \
|
||||
MOVL t, 13*4+off+320(dst); \
|
||||
MOVL t, 4*4+off+384(dst); \
|
||||
MOVL t, 8*4+off+448(dst); \
|
||||
MOVL t, 15*4+off+512(dst); \
|
||||
MOVL t, 7*4+off+576(dst); \
|
||||
MOVL 6*4(src), t; \
|
||||
MOVL t, 3*4+off+0(dst); \
|
||||
MOVL t, 7*4+off+64(dst); \
|
||||
MOVL t, 13*4+off+128(dst); \
|
||||
MOVL t, 12*4+off+192(dst); \
|
||||
MOVL t, 10*4+off+256(dst); \
|
||||
MOVL t, 1*4+off+320(dst); \
|
||||
MOVL t, 9*4+off+384(dst); \
|
||||
MOVL t, 14*4+off+448(dst); \
|
||||
MOVL t, 0*4+off+512(dst); \
|
||||
MOVL t, 6*4+off+576(dst); \
|
||||
MOVL 7*4(src), t; \
|
||||
MOVL t, 7*4+off+0(dst); \
|
||||
MOVL t, 14*4+off+64(dst); \
|
||||
MOVL t, 10*4+off+128(dst); \
|
||||
MOVL t, 0*4+off+192(dst); \
|
||||
MOVL t, 5*4+off+256(dst); \
|
||||
MOVL t, 9*4+off+320(dst); \
|
||||
MOVL t, 12*4+off+384(dst); \
|
||||
MOVL t, 1*4+off+448(dst); \
|
||||
MOVL t, 13*4+off+512(dst); \
|
||||
MOVL t, 2*4+off+576(dst); \
|
||||
MOVL 8*4(src), t; \
|
||||
MOVL t, 8*4+off+0(dst); \
|
||||
MOVL t, 5*4+off+64(dst); \
|
||||
MOVL t, 4*4+off+128(dst); \
|
||||
MOVL t, 15*4+off+192(dst); \
|
||||
MOVL t, 14*4+off+256(dst); \
|
||||
MOVL t, 3*4+off+320(dst); \
|
||||
MOVL t, 11*4+off+384(dst); \
|
||||
MOVL t, 10*4+off+448(dst); \
|
||||
MOVL t, 7*4+off+512(dst); \
|
||||
MOVL t, 1*4+off+576(dst); \
|
||||
MOVL 9*4(src), t; \
|
||||
MOVL t, 12*4+off+0(dst); \
|
||||
MOVL t, 2*4+off+64(dst); \
|
||||
MOVL t, 11*4+off+128(dst); \
|
||||
MOVL t, 4*4+off+192(dst); \
|
||||
MOVL t, 0*4+off+256(dst); \
|
||||
MOVL t, 15*4+off+320(dst); \
|
||||
MOVL t, 10*4+off+384(dst); \
|
||||
MOVL t, 7*4+off+448(dst); \
|
||||
MOVL t, 5*4+off+512(dst); \
|
||||
MOVL t, 9*4+off+576(dst); \
|
||||
MOVL 10*4(src), t; \
|
||||
MOVL t, 9*4+off+0(dst); \
|
||||
MOVL t, 4*4+off+64(dst); \
|
||||
MOVL t, 8*4+off+128(dst); \
|
||||
MOVL t, 13*4+off+192(dst); \
|
||||
MOVL t, 3*4+off+256(dst); \
|
||||
MOVL t, 5*4+off+320(dst); \
|
||||
MOVL t, 7*4+off+384(dst); \
|
||||
MOVL t, 15*4+off+448(dst); \
|
||||
MOVL t, 11*4+off+512(dst); \
|
||||
MOVL t, 0*4+off+576(dst); \
|
||||
MOVL 11*4(src), t; \
|
||||
MOVL t, 13*4+off+0(dst); \
|
||||
MOVL t, 10*4+off+64(dst); \
|
||||
MOVL t, 0*4+off+128(dst); \
|
||||
MOVL t, 3*4+off+192(dst); \
|
||||
MOVL t, 9*4+off+256(dst); \
|
||||
MOVL t, 6*4+off+320(dst); \
|
||||
MOVL t, 15*4+off+384(dst); \
|
||||
MOVL t, 4*4+off+448(dst); \
|
||||
MOVL t, 2*4+off+512(dst); \
|
||||
MOVL t, 12*4+off+576(dst); \
|
||||
MOVL 12*4(src), t; \
|
||||
MOVL t, 10*4+off+0(dst); \
|
||||
MOVL t, 12*4+off+64(dst); \
|
||||
MOVL t, 1*4+off+128(dst); \
|
||||
MOVL t, 6*4+off+192(dst); \
|
||||
MOVL t, 13*4+off+256(dst); \
|
||||
MOVL t, 4*4+off+320(dst); \
|
||||
MOVL t, 0*4+off+384(dst); \
|
||||
MOVL t, 2*4+off+448(dst); \
|
||||
MOVL t, 8*4+off+512(dst); \
|
||||
MOVL t, 14*4+off+576(dst); \
|
||||
MOVL 13*4(src), t; \
|
||||
MOVL t, 14*4+off+0(dst); \
|
||||
MOVL t, 3*4+off+64(dst); \
|
||||
MOVL t, 7*4+off+128(dst); \
|
||||
MOVL t, 2*4+off+192(dst); \
|
||||
MOVL t, 15*4+off+256(dst); \
|
||||
MOVL t, 12*4+off+320(dst); \
|
||||
MOVL t, 6*4+off+384(dst); \
|
||||
MOVL t, 0*4+off+448(dst); \
|
||||
MOVL t, 9*4+off+512(dst); \
|
||||
MOVL t, 11*4+off+576(dst); \
|
||||
MOVL 14*4(src), t; \
|
||||
MOVL t, 11*4+off+0(dst); \
|
||||
MOVL t, 0*4+off+64(dst); \
|
||||
MOVL t, 12*4+off+128(dst); \
|
||||
MOVL t, 7*4+off+192(dst); \
|
||||
MOVL t, 8*4+off+256(dst); \
|
||||
MOVL t, 14*4+off+320(dst); \
|
||||
MOVL t, 2*4+off+384(dst); \
|
||||
MOVL t, 5*4+off+448(dst); \
|
||||
MOVL t, 1*4+off+512(dst); \
|
||||
MOVL t, 13*4+off+576(dst); \
|
||||
MOVL 15*4(src), t; \
|
||||
MOVL t, 15*4+off+0(dst); \
|
||||
MOVL t, 6*4+off+64(dst); \
|
||||
MOVL t, 3*4+off+128(dst); \
|
||||
MOVL t, 11*4+off+192(dst); \
|
||||
MOVL t, 7*4+off+256(dst); \
|
||||
MOVL t, 10*4+off+320(dst); \
|
||||
MOVL t, 5*4+off+384(dst); \
|
||||
MOVL t, 9*4+off+448(dst); \
|
||||
MOVL t, 4*4+off+512(dst); \
|
||||
MOVL t, 8*4+off+576(dst)
|
||||
|
||||
// func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
TEXT ·hashBlocksSSE2(SB), 0, $672-24 // frame = 656 + 16 byte alignment
|
||||
MOVL h+0(FP), AX
|
||||
MOVL c+4(FP), BX
|
||||
MOVL flag+8(FP), CX
|
||||
MOVL blocks_base+12(FP), SI
|
||||
MOVL blocks_len+16(FP), DX
|
||||
|
||||
MOVL SP, BP
|
||||
MOVL SP, DI
|
||||
ADDL $15, DI
|
||||
ANDL $~15, DI
|
||||
MOVL DI, SP
|
||||
|
||||
MOVL CX, 8(SP)
|
||||
MOVL 0(BX), CX
|
||||
MOVL CX, 0(SP)
|
||||
MOVL 4(BX), CX
|
||||
MOVL CX, 4(SP)
|
||||
XORL CX, CX
|
||||
MOVL CX, 12(SP)
|
||||
|
||||
MOVOU 0(AX), X0
|
||||
MOVOU 16(AX), X1
|
||||
MOVOU counter<>(SB), X2
|
||||
|
||||
loop:
|
||||
MOVO X0, X4
|
||||
MOVO X1, X5
|
||||
MOVOU iv0<>(SB), X6
|
||||
MOVOU iv1<>(SB), X7
|
||||
|
||||
MOVO 0(SP), X3
|
||||
PADDQ X2, X3
|
||||
PXOR X3, X7
|
||||
MOVO X3, 0(SP)
|
||||
|
||||
PRECOMPUTE(SP, 16, SI, CX)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+64(SP), 32+64(SP), 48+64(SP), 64+64(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+128(SP), 32+128(SP), 48+128(SP), 64+128(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+192(SP), 32+192(SP), 48+192(SP), 64+192(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+256(SP), 32+256(SP), 48+256(SP), 64+256(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+320(SP), 32+320(SP), 48+320(SP), 64+320(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+384(SP), 32+384(SP), 48+384(SP), 64+384(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+448(SP), 32+448(SP), 48+448(SP), 64+448(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+512(SP), 32+512(SP), 48+512(SP), 64+512(SP), X3)
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+576(SP), 32+576(SP), 48+576(SP), 64+576(SP), X3)
|
||||
|
||||
PXOR X4, X0
|
||||
PXOR X5, X1
|
||||
PXOR X6, X0
|
||||
PXOR X7, X1
|
||||
|
||||
LEAL 64(SI), SI
|
||||
SUBL $64, DX
|
||||
JNE loop
|
||||
|
||||
MOVL 0(SP), CX
|
||||
MOVL CX, 0(BX)
|
||||
MOVL 4(SP), CX
|
||||
MOVL CX, 4(BX)
|
||||
|
||||
MOVOU X0, 0(AX)
|
||||
MOVOU X1, 16(AX)
|
||||
|
||||
MOVL BP, SP
|
||||
RET
|
||||
|
||||
// func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
TEXT ·hashBlocksSSSE3(SB), 0, $704-24 // frame = 688 + 16 byte alignment
|
||||
MOVL h+0(FP), AX
|
||||
MOVL c+4(FP), BX
|
||||
MOVL flag+8(FP), CX
|
||||
MOVL blocks_base+12(FP), SI
|
||||
MOVL blocks_len+16(FP), DX
|
||||
|
||||
MOVL SP, BP
|
||||
MOVL SP, DI
|
||||
ADDL $15, DI
|
||||
ANDL $~15, DI
|
||||
MOVL DI, SP
|
||||
|
||||
MOVL CX, 8(SP)
|
||||
MOVL 0(BX), CX
|
||||
MOVL CX, 0(SP)
|
||||
MOVL 4(BX), CX
|
||||
MOVL CX, 4(SP)
|
||||
XORL CX, CX
|
||||
MOVL CX, 12(SP)
|
||||
|
||||
MOVOU 0(AX), X0
|
||||
MOVOU 16(AX), X1
|
||||
MOVOU counter<>(SB), X2
|
||||
|
||||
loop:
|
||||
MOVO X0, 656(SP)
|
||||
MOVO X1, 672(SP)
|
||||
MOVO X0, X4
|
||||
MOVO X1, X5
|
||||
MOVOU iv0<>(SB), X6
|
||||
MOVOU iv1<>(SB), X7
|
||||
|
||||
MOVO 0(SP), X3
|
||||
PADDQ X2, X3
|
||||
PXOR X3, X7
|
||||
MOVO X3, 0(SP)
|
||||
|
||||
MOVOU rol16<>(SB), X0
|
||||
MOVOU rol8<>(SB), X1
|
||||
|
||||
PRECOMPUTE(SP, 16, SI, CX)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+64(SP), 32+64(SP), 48+64(SP), 64+64(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+128(SP), 32+128(SP), 48+128(SP), 64+128(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+192(SP), 32+192(SP), 48+192(SP), 64+192(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+256(SP), 32+256(SP), 48+256(SP), 64+256(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+320(SP), 32+320(SP), 48+320(SP), 64+320(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+384(SP), 32+384(SP), 48+384(SP), 64+384(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+448(SP), 32+448(SP), 48+448(SP), 64+448(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+512(SP), 32+512(SP), 48+512(SP), 64+512(SP), X3, X0, X1)
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+576(SP), 32+576(SP), 48+576(SP), 64+576(SP), X3, X0, X1)
|
||||
|
||||
MOVO 656(SP), X0
|
||||
MOVO 672(SP), X1
|
||||
PXOR X4, X0
|
||||
PXOR X5, X1
|
||||
PXOR X6, X0
|
||||
PXOR X7, X1
|
||||
|
||||
LEAL 64(SI), SI
|
||||
SUBL $64, DX
|
||||
JNE loop
|
||||
|
||||
MOVL 0(SP), CX
|
||||
MOVL CX, 0(BX)
|
||||
MOVL 4(SP), CX
|
||||
MOVL CX, 4(BX)
|
||||
|
||||
MOVOU X0, 0(AX)
|
||||
MOVOU X1, 16(AX)
|
||||
|
||||
MOVL BP, SP
|
||||
RET
|
||||
|
||||
// func supportSSSE3() bool
|
||||
TEXT ·supportSSSE3(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
MOVL CX, BX
|
||||
ANDL $0x1, BX // supports SSE3
|
||||
JZ FALSE
|
||||
ANDL $0x200, CX // supports SSSE3
|
||||
JZ FALSE
|
||||
MOVB $1, ret+0(FP)
|
||||
RET
|
||||
|
||||
FALSE:
|
||||
MOVB $0, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func supportSSE2() bool
|
||||
TEXT ·supportSSE2(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
SHRL $26, DX
|
||||
ANDL $1, DX // DX != 0 if support SSE2
|
||||
MOVB DX, ret+0(FP)
|
||||
RET
|
|
@ -0,0 +1,40 @@
|
|||
// 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.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
package blake2s
|
||||
|
||||
var (
|
||||
useSSE4 = supportSSE4()
|
||||
useSSSE3 = supportSSSE3()
|
||||
useSSE2 = true // Always available on amd64
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func supportSSSE3() bool
|
||||
|
||||
//go:noescape
|
||||
func supportSSE4() bool
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
//go:noescape
|
||||
func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
|
||||
func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
|
||||
if useSSE4 {
|
||||
hashBlocksSSE4(h, c, flag, blocks)
|
||||
} else if useSSSE3 {
|
||||
hashBlocksSSSE3(h, c, flag, blocks)
|
||||
} else if useSSE2 {
|
||||
hashBlocksSSE2(h, c, flag, blocks)
|
||||
} else {
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,463 @@
|
|||
// 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.
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
DATA iv0<>+0x00(SB)/4, $0x6a09e667
|
||||
DATA iv0<>+0x04(SB)/4, $0xbb67ae85
|
||||
DATA iv0<>+0x08(SB)/4, $0x3c6ef372
|
||||
DATA iv0<>+0x0c(SB)/4, $0xa54ff53a
|
||||
GLOBL iv0<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA iv1<>+0x00(SB)/4, $0x510e527f
|
||||
DATA iv1<>+0x04(SB)/4, $0x9b05688c
|
||||
DATA iv1<>+0x08(SB)/4, $0x1f83d9ab
|
||||
DATA iv1<>+0x0c(SB)/4, $0x5be0cd19
|
||||
GLOBL iv1<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA rol16<>+0x00(SB)/8, $0x0504070601000302
|
||||
DATA rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A
|
||||
GLOBL rol16<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA rol8<>+0x00(SB)/8, $0x0407060500030201
|
||||
DATA rol8<>+0x08(SB)/8, $0x0C0F0E0D080B0A09
|
||||
GLOBL rol8<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
DATA counter<>+0x00(SB)/8, $0x40
|
||||
DATA counter<>+0x08(SB)/8, $0x0
|
||||
GLOBL counter<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
#define ROTL_SSE2(n, t, v) \
|
||||
MOVO v, t; \
|
||||
PSLLL $n, t; \
|
||||
PSRLL $(32-n), v; \
|
||||
PXOR t, v
|
||||
|
||||
#define ROTL_SSSE3(c, v) \
|
||||
PSHUFB c, v
|
||||
|
||||
#define ROUND_SSE2(v0, v1, v2, v3, m0, m1, m2, m3, t) \
|
||||
PADDL m0, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSE2(16, t, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(20, t, v1); \
|
||||
PADDL m1, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSE2(24, t, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(25, t, v1); \
|
||||
PSHUFL $0x39, v1, v1; \
|
||||
PSHUFL $0x4E, v2, v2; \
|
||||
PSHUFL $0x93, v3, v3; \
|
||||
PADDL m2, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSE2(16, t, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(20, t, v1); \
|
||||
PADDL m3, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSE2(24, t, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(25, t, v1); \
|
||||
PSHUFL $0x39, v3, v3; \
|
||||
PSHUFL $0x4E, v2, v2; \
|
||||
PSHUFL $0x93, v1, v1
|
||||
|
||||
#define ROUND_SSSE3(v0, v1, v2, v3, m0, m1, m2, m3, t, c16, c8) \
|
||||
PADDL m0, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSSE3(c16, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(20, t, v1); \
|
||||
PADDL m1, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSSE3(c8, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(25, t, v1); \
|
||||
PSHUFL $0x39, v1, v1; \
|
||||
PSHUFL $0x4E, v2, v2; \
|
||||
PSHUFL $0x93, v3, v3; \
|
||||
PADDL m2, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSSE3(c16, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(20, t, v1); \
|
||||
PADDL m3, v0; \
|
||||
PADDL v1, v0; \
|
||||
PXOR v0, v3; \
|
||||
ROTL_SSSE3(c8, v3); \
|
||||
PADDL v3, v2; \
|
||||
PXOR v2, v1; \
|
||||
ROTL_SSE2(25, t, v1); \
|
||||
PSHUFL $0x39, v3, v3; \
|
||||
PSHUFL $0x4E, v2, v2; \
|
||||
PSHUFL $0x93, v1, v1
|
||||
|
||||
|
||||
#define LOAD_MSG_SSE4(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15) \
|
||||
MOVL i0*4(src), m0; \
|
||||
PINSRD $1, i1*4(src), m0; \
|
||||
PINSRD $2, i2*4(src), m0; \
|
||||
PINSRD $3, i3*4(src), m0; \
|
||||
MOVL i4*4(src), m1; \
|
||||
PINSRD $1, i5*4(src), m1; \
|
||||
PINSRD $2, i6*4(src), m1; \
|
||||
PINSRD $3, i7*4(src), m1; \
|
||||
MOVL i8*4(src), m2; \
|
||||
PINSRD $1, i9*4(src), m2; \
|
||||
PINSRD $2, i10*4(src), m2; \
|
||||
PINSRD $3, i11*4(src), m2; \
|
||||
MOVL i12*4(src), m3; \
|
||||
PINSRD $1, i13*4(src), m3; \
|
||||
PINSRD $2, i14*4(src), m3; \
|
||||
PINSRD $3, i15*4(src), m3
|
||||
|
||||
#define PRECOMPUTE_MSG(dst, off, src, R8, R9, R10, R11, R12, R13, R14, R15) \
|
||||
MOVQ 0*4(src), R8; \
|
||||
MOVQ 2*4(src), R9; \
|
||||
MOVQ 4*4(src), R10; \
|
||||
MOVQ 6*4(src), R11; \
|
||||
MOVQ 8*4(src), R12; \
|
||||
MOVQ 10*4(src), R13; \
|
||||
MOVQ 12*4(src), R14; \
|
||||
MOVQ 14*4(src), R15; \
|
||||
\
|
||||
MOVL R8, 0*4+off+0(dst); \
|
||||
MOVL R8, 9*4+off+64(dst); \
|
||||
MOVL R8, 5*4+off+128(dst); \
|
||||
MOVL R8, 14*4+off+192(dst); \
|
||||
MOVL R8, 4*4+off+256(dst); \
|
||||
MOVL R8, 2*4+off+320(dst); \
|
||||
MOVL R8, 8*4+off+384(dst); \
|
||||
MOVL R8, 12*4+off+448(dst); \
|
||||
MOVL R8, 3*4+off+512(dst); \
|
||||
MOVL R8, 15*4+off+576(dst); \
|
||||
SHRQ $32, R8; \
|
||||
MOVL R8, 4*4+off+0(dst); \
|
||||
MOVL R8, 8*4+off+64(dst); \
|
||||
MOVL R8, 14*4+off+128(dst); \
|
||||
MOVL R8, 5*4+off+192(dst); \
|
||||
MOVL R8, 12*4+off+256(dst); \
|
||||
MOVL R8, 11*4+off+320(dst); \
|
||||
MOVL R8, 1*4+off+384(dst); \
|
||||
MOVL R8, 6*4+off+448(dst); \
|
||||
MOVL R8, 10*4+off+512(dst); \
|
||||
MOVL R8, 3*4+off+576(dst); \
|
||||
\
|
||||
MOVL R9, 1*4+off+0(dst); \
|
||||
MOVL R9, 13*4+off+64(dst); \
|
||||
MOVL R9, 6*4+off+128(dst); \
|
||||
MOVL R9, 8*4+off+192(dst); \
|
||||
MOVL R9, 2*4+off+256(dst); \
|
||||
MOVL R9, 0*4+off+320(dst); \
|
||||
MOVL R9, 14*4+off+384(dst); \
|
||||
MOVL R9, 11*4+off+448(dst); \
|
||||
MOVL R9, 12*4+off+512(dst); \
|
||||
MOVL R9, 4*4+off+576(dst); \
|
||||
SHRQ $32, R9; \
|
||||
MOVL R9, 5*4+off+0(dst); \
|
||||
MOVL R9, 15*4+off+64(dst); \
|
||||
MOVL R9, 9*4+off+128(dst); \
|
||||
MOVL R9, 1*4+off+192(dst); \
|
||||
MOVL R9, 11*4+off+256(dst); \
|
||||
MOVL R9, 7*4+off+320(dst); \
|
||||
MOVL R9, 13*4+off+384(dst); \
|
||||
MOVL R9, 3*4+off+448(dst); \
|
||||
MOVL R9, 6*4+off+512(dst); \
|
||||
MOVL R9, 10*4+off+576(dst); \
|
||||
\
|
||||
MOVL R10, 2*4+off+0(dst); \
|
||||
MOVL R10, 1*4+off+64(dst); \
|
||||
MOVL R10, 15*4+off+128(dst); \
|
||||
MOVL R10, 10*4+off+192(dst); \
|
||||
MOVL R10, 6*4+off+256(dst); \
|
||||
MOVL R10, 8*4+off+320(dst); \
|
||||
MOVL R10, 3*4+off+384(dst); \
|
||||
MOVL R10, 13*4+off+448(dst); \
|
||||
MOVL R10, 14*4+off+512(dst); \
|
||||
MOVL R10, 5*4+off+576(dst); \
|
||||
SHRQ $32, R10; \
|
||||
MOVL R10, 6*4+off+0(dst); \
|
||||
MOVL R10, 11*4+off+64(dst); \
|
||||
MOVL R10, 2*4+off+128(dst); \
|
||||
MOVL R10, 9*4+off+192(dst); \
|
||||
MOVL R10, 1*4+off+256(dst); \
|
||||
MOVL R10, 13*4+off+320(dst); \
|
||||
MOVL R10, 4*4+off+384(dst); \
|
||||
MOVL R10, 8*4+off+448(dst); \
|
||||
MOVL R10, 15*4+off+512(dst); \
|
||||
MOVL R10, 7*4+off+576(dst); \
|
||||
\
|
||||
MOVL R11, 3*4+off+0(dst); \
|
||||
MOVL R11, 7*4+off+64(dst); \
|
||||
MOVL R11, 13*4+off+128(dst); \
|
||||
MOVL R11, 12*4+off+192(dst); \
|
||||
MOVL R11, 10*4+off+256(dst); \
|
||||
MOVL R11, 1*4+off+320(dst); \
|
||||
MOVL R11, 9*4+off+384(dst); \
|
||||
MOVL R11, 14*4+off+448(dst); \
|
||||
MOVL R11, 0*4+off+512(dst); \
|
||||
MOVL R11, 6*4+off+576(dst); \
|
||||
SHRQ $32, R11; \
|
||||
MOVL R11, 7*4+off+0(dst); \
|
||||
MOVL R11, 14*4+off+64(dst); \
|
||||
MOVL R11, 10*4+off+128(dst); \
|
||||
MOVL R11, 0*4+off+192(dst); \
|
||||
MOVL R11, 5*4+off+256(dst); \
|
||||
MOVL R11, 9*4+off+320(dst); \
|
||||
MOVL R11, 12*4+off+384(dst); \
|
||||
MOVL R11, 1*4+off+448(dst); \
|
||||
MOVL R11, 13*4+off+512(dst); \
|
||||
MOVL R11, 2*4+off+576(dst); \
|
||||
\
|
||||
MOVL R12, 8*4+off+0(dst); \
|
||||
MOVL R12, 5*4+off+64(dst); \
|
||||
MOVL R12, 4*4+off+128(dst); \
|
||||
MOVL R12, 15*4+off+192(dst); \
|
||||
MOVL R12, 14*4+off+256(dst); \
|
||||
MOVL R12, 3*4+off+320(dst); \
|
||||
MOVL R12, 11*4+off+384(dst); \
|
||||
MOVL R12, 10*4+off+448(dst); \
|
||||
MOVL R12, 7*4+off+512(dst); \
|
||||
MOVL R12, 1*4+off+576(dst); \
|
||||
SHRQ $32, R12; \
|
||||
MOVL R12, 12*4+off+0(dst); \
|
||||
MOVL R12, 2*4+off+64(dst); \
|
||||
MOVL R12, 11*4+off+128(dst); \
|
||||
MOVL R12, 4*4+off+192(dst); \
|
||||
MOVL R12, 0*4+off+256(dst); \
|
||||
MOVL R12, 15*4+off+320(dst); \
|
||||
MOVL R12, 10*4+off+384(dst); \
|
||||
MOVL R12, 7*4+off+448(dst); \
|
||||
MOVL R12, 5*4+off+512(dst); \
|
||||
MOVL R12, 9*4+off+576(dst); \
|
||||
\
|
||||
MOVL R13, 9*4+off+0(dst); \
|
||||
MOVL R13, 4*4+off+64(dst); \
|
||||
MOVL R13, 8*4+off+128(dst); \
|
||||
MOVL R13, 13*4+off+192(dst); \
|
||||
MOVL R13, 3*4+off+256(dst); \
|
||||
MOVL R13, 5*4+off+320(dst); \
|
||||
MOVL R13, 7*4+off+384(dst); \
|
||||
MOVL R13, 15*4+off+448(dst); \
|
||||
MOVL R13, 11*4+off+512(dst); \
|
||||
MOVL R13, 0*4+off+576(dst); \
|
||||
SHRQ $32, R13; \
|
||||
MOVL R13, 13*4+off+0(dst); \
|
||||
MOVL R13, 10*4+off+64(dst); \
|
||||
MOVL R13, 0*4+off+128(dst); \
|
||||
MOVL R13, 3*4+off+192(dst); \
|
||||
MOVL R13, 9*4+off+256(dst); \
|
||||
MOVL R13, 6*4+off+320(dst); \
|
||||
MOVL R13, 15*4+off+384(dst); \
|
||||
MOVL R13, 4*4+off+448(dst); \
|
||||
MOVL R13, 2*4+off+512(dst); \
|
||||
MOVL R13, 12*4+off+576(dst); \
|
||||
\
|
||||
MOVL R14, 10*4+off+0(dst); \
|
||||
MOVL R14, 12*4+off+64(dst); \
|
||||
MOVL R14, 1*4+off+128(dst); \
|
||||
MOVL R14, 6*4+off+192(dst); \
|
||||
MOVL R14, 13*4+off+256(dst); \
|
||||
MOVL R14, 4*4+off+320(dst); \
|
||||
MOVL R14, 0*4+off+384(dst); \
|
||||
MOVL R14, 2*4+off+448(dst); \
|
||||
MOVL R14, 8*4+off+512(dst); \
|
||||
MOVL R14, 14*4+off+576(dst); \
|
||||
SHRQ $32, R14; \
|
||||
MOVL R14, 14*4+off+0(dst); \
|
||||
MOVL R14, 3*4+off+64(dst); \
|
||||
MOVL R14, 7*4+off+128(dst); \
|
||||
MOVL R14, 2*4+off+192(dst); \
|
||||
MOVL R14, 15*4+off+256(dst); \
|
||||
MOVL R14, 12*4+off+320(dst); \
|
||||
MOVL R14, 6*4+off+384(dst); \
|
||||
MOVL R14, 0*4+off+448(dst); \
|
||||
MOVL R14, 9*4+off+512(dst); \
|
||||
MOVL R14, 11*4+off+576(dst); \
|
||||
\
|
||||
MOVL R15, 11*4+off+0(dst); \
|
||||
MOVL R15, 0*4+off+64(dst); \
|
||||
MOVL R15, 12*4+off+128(dst); \
|
||||
MOVL R15, 7*4+off+192(dst); \
|
||||
MOVL R15, 8*4+off+256(dst); \
|
||||
MOVL R15, 14*4+off+320(dst); \
|
||||
MOVL R15, 2*4+off+384(dst); \
|
||||
MOVL R15, 5*4+off+448(dst); \
|
||||
MOVL R15, 1*4+off+512(dst); \
|
||||
MOVL R15, 13*4+off+576(dst); \
|
||||
SHRQ $32, R15; \
|
||||
MOVL R15, 15*4+off+0(dst); \
|
||||
MOVL R15, 6*4+off+64(dst); \
|
||||
MOVL R15, 3*4+off+128(dst); \
|
||||
MOVL R15, 11*4+off+192(dst); \
|
||||
MOVL R15, 7*4+off+256(dst); \
|
||||
MOVL R15, 10*4+off+320(dst); \
|
||||
MOVL R15, 5*4+off+384(dst); \
|
||||
MOVL R15, 9*4+off+448(dst); \
|
||||
MOVL R15, 4*4+off+512(dst); \
|
||||
MOVL R15, 8*4+off+576(dst)
|
||||
|
||||
#define BLAKE2s_SSE2() \
|
||||
PRECOMPUTE_MSG(SP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+64(SP), 32+64(SP), 48+64(SP), 64+64(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+128(SP), 32+128(SP), 48+128(SP), 64+128(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+192(SP), 32+192(SP), 48+192(SP), 64+192(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+256(SP), 32+256(SP), 48+256(SP), 64+256(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+320(SP), 32+320(SP), 48+320(SP), 64+320(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+384(SP), 32+384(SP), 48+384(SP), 64+384(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+448(SP), 32+448(SP), 48+448(SP), 64+448(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+512(SP), 32+512(SP), 48+512(SP), 64+512(SP), X8); \
|
||||
ROUND_SSE2(X4, X5, X6, X7, 16+576(SP), 32+576(SP), 48+576(SP), 64+576(SP), X8)
|
||||
|
||||
#define BLAKE2s_SSSE3() \
|
||||
PRECOMPUTE_MSG(SP, 16, SI, R8, R9, R10, R11, R12, R13, R14, R15); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+64(SP), 32+64(SP), 48+64(SP), 64+64(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+128(SP), 32+128(SP), 48+128(SP), 64+128(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+192(SP), 32+192(SP), 48+192(SP), 64+192(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+256(SP), 32+256(SP), 48+256(SP), 64+256(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+320(SP), 32+320(SP), 48+320(SP), 64+320(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+384(SP), 32+384(SP), 48+384(SP), 64+384(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+448(SP), 32+448(SP), 48+448(SP), 64+448(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+512(SP), 32+512(SP), 48+512(SP), 64+512(SP), X8, X13, X14); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, 16+576(SP), 32+576(SP), 48+576(SP), 64+576(SP), X8, X13, X14)
|
||||
|
||||
#define BLAKE2s_SSE4() \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14); \
|
||||
LOAD_MSG_SSE4(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0); \
|
||||
ROUND_SSSE3(X4, X5, X6, X7, X8, X9, X10, X11, X8, X13, X14)
|
||||
|
||||
#define HASH_BLOCKS(h, c, flag, blocks_base, blocks_len, BLAKE2s_FUNC) \
|
||||
MOVQ h, AX; \
|
||||
MOVQ c, BX; \
|
||||
MOVL flag, CX; \
|
||||
MOVQ blocks_base, SI; \
|
||||
MOVQ blocks_len, DX; \
|
||||
\
|
||||
MOVQ SP, BP; \
|
||||
MOVQ SP, R9; \
|
||||
ADDQ $15, R9; \
|
||||
ANDQ $~15, R9; \
|
||||
MOVQ R9, SP; \
|
||||
\
|
||||
MOVQ 0(BX), R9; \
|
||||
MOVQ R9, 0(SP); \
|
||||
XORQ R9, R9; \
|
||||
MOVQ R9, 8(SP); \
|
||||
MOVL CX, 8(SP); \
|
||||
\
|
||||
MOVOU 0(AX), X0; \
|
||||
MOVOU 16(AX), X1; \
|
||||
MOVOU iv0<>(SB), X2; \
|
||||
MOVOU iv1<>(SB), X3 \
|
||||
\
|
||||
MOVOU counter<>(SB), X12; \
|
||||
MOVOU rol16<>(SB), X13; \
|
||||
MOVOU rol8<>(SB), X14; \
|
||||
MOVO 0(SP), X15; \
|
||||
\
|
||||
loop: \
|
||||
MOVO X0, X4; \
|
||||
MOVO X1, X5; \
|
||||
MOVO X2, X6; \
|
||||
MOVO X3, X7; \
|
||||
\
|
||||
PADDQ X12, X15; \
|
||||
PXOR X15, X7; \
|
||||
\
|
||||
BLAKE2s_FUNC(); \
|
||||
\
|
||||
PXOR X4, X0; \
|
||||
PXOR X5, X1; \
|
||||
PXOR X6, X0; \
|
||||
PXOR X7, X1; \
|
||||
\
|
||||
LEAQ 64(SI), SI; \
|
||||
SUBQ $64, DX; \
|
||||
JNE loop; \
|
||||
\
|
||||
MOVO X15, 0(SP); \
|
||||
MOVQ 0(SP), R9; \
|
||||
MOVQ R9, 0(BX); \
|
||||
\
|
||||
MOVOU X0, 0(AX); \
|
||||
MOVOU X1, 16(AX); \
|
||||
\
|
||||
MOVQ BP, SP
|
||||
|
||||
// func hashBlocksSSE2(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
TEXT ·hashBlocksSSE2(SB), 0, $672-48 // frame = 656 + 16 byte alignment
|
||||
HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE2)
|
||||
RET
|
||||
|
||||
// func hashBlocksSSSE3(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
TEXT ·hashBlocksSSSE3(SB), 0, $672-48 // frame = 656 + 16 byte alignment
|
||||
HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSSE3)
|
||||
RET
|
||||
|
||||
// func hashBlocksSSE4(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte)
|
||||
TEXT ·hashBlocksSSE4(SB), 0, $32-48 // frame = 16 + 16 byte alignment
|
||||
HASH_BLOCKS(h+0(FP), c+8(FP), flag+16(FP), blocks_base+24(FP), blocks_len+32(FP), BLAKE2s_SSE4)
|
||||
RET
|
||||
|
||||
// func supportSSE4() bool
|
||||
TEXT ·supportSSE4(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
SHRL $19, CX // Bit 19 indicates SSE4.1.
|
||||
ANDL $1, CX
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func supportSSSE3() bool
|
||||
TEXT ·supportSSSE3(SB), 4, $0-1
|
||||
MOVL $1, AX
|
||||
CPUID
|
||||
MOVL CX, BX
|
||||
ANDL $0x1, BX // Bit zero indicates SSE3 support.
|
||||
JZ FALSE
|
||||
ANDL $0x200, CX // Bit nine indicates SSSE3 support.
|
||||
JZ FALSE
|
||||
MOVB $1, ret+0(FP)
|
||||
RET
|
||||
|
||||
FALSE:
|
||||
MOVB $0, ret+0(FP)
|
||||
RET
|
|
@ -0,0 +1,174 @@
|
|||
// 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 blake2s
|
||||
|
||||
// the precomputed values for BLAKE2s
|
||||
// there are 10 16-byte arrays - one for each round
|
||||
// the entries are calculated from the sigma constants.
|
||||
var precomputed = [10][16]byte{
|
||||
{0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15},
|
||||
{14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3},
|
||||
{11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4},
|
||||
{7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8},
|
||||
{9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13},
|
||||
{2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9},
|
||||
{12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11},
|
||||
{13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10},
|
||||
{6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5},
|
||||
{10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0},
|
||||
}
|
||||
|
||||
func hashBlocksGeneric(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
|
||||
var m [16]uint32
|
||||
c0, c1 := c[0], c[1]
|
||||
|
||||
for i := 0; i < len(blocks); {
|
||||
c0 += BlockSize
|
||||
if c0 < BlockSize {
|
||||
c1++
|
||||
}
|
||||
|
||||
v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7]
|
||||
v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]
|
||||
v12 ^= c0
|
||||
v13 ^= c1
|
||||
v14 ^= flag
|
||||
|
||||
for j := range m {
|
||||
m[j] = uint32(blocks[i]) | uint32(blocks[i+1])<<8 | uint32(blocks[i+2])<<16 | uint32(blocks[i+3])<<24
|
||||
i += 4
|
||||
}
|
||||
|
||||
for k := range precomputed {
|
||||
s := &(precomputed[k])
|
||||
|
||||
v0 += m[s[0]]
|
||||
v0 += v4
|
||||
v12 ^= v0
|
||||
v12 = v12<<(32-16) | v12>>16
|
||||
v8 += v12
|
||||
v4 ^= v8
|
||||
v4 = v4<<(32-12) | v4>>12
|
||||
v1 += m[s[1]]
|
||||
v1 += v5
|
||||
v13 ^= v1
|
||||
v13 = v13<<(32-16) | v13>>16
|
||||
v9 += v13
|
||||
v5 ^= v9
|
||||
v5 = v5<<(32-12) | v5>>12
|
||||
v2 += m[s[2]]
|
||||
v2 += v6
|
||||
v14 ^= v2
|
||||
v14 = v14<<(32-16) | v14>>16
|
||||
v10 += v14
|
||||
v6 ^= v10
|
||||
v6 = v6<<(32-12) | v6>>12
|
||||
v3 += m[s[3]]
|
||||
v3 += v7
|
||||
v15 ^= v3
|
||||
v15 = v15<<(32-16) | v15>>16
|
||||
v11 += v15
|
||||
v7 ^= v11
|
||||
v7 = v7<<(32-12) | v7>>12
|
||||
|
||||
v0 += m[s[4]]
|
||||
v0 += v4
|
||||
v12 ^= v0
|
||||
v12 = v12<<(32-8) | v12>>8
|
||||
v8 += v12
|
||||
v4 ^= v8
|
||||
v4 = v4<<(32-7) | v4>>7
|
||||
v1 += m[s[5]]
|
||||
v1 += v5
|
||||
v13 ^= v1
|
||||
v13 = v13<<(32-8) | v13>>8
|
||||
v9 += v13
|
||||
v5 ^= v9
|
||||
v5 = v5<<(32-7) | v5>>7
|
||||
v2 += m[s[6]]
|
||||
v2 += v6
|
||||
v14 ^= v2
|
||||
v14 = v14<<(32-8) | v14>>8
|
||||
v10 += v14
|
||||
v6 ^= v10
|
||||
v6 = v6<<(32-7) | v6>>7
|
||||
v3 += m[s[7]]
|
||||
v3 += v7
|
||||
v15 ^= v3
|
||||
v15 = v15<<(32-8) | v15>>8
|
||||
v11 += v15
|
||||
v7 ^= v11
|
||||
v7 = v7<<(32-7) | v7>>7
|
||||
|
||||
v0 += m[s[8]]
|
||||
v0 += v5
|
||||
v15 ^= v0
|
||||
v15 = v15<<(32-16) | v15>>16
|
||||
v10 += v15
|
||||
v5 ^= v10
|
||||
v5 = v5<<(32-12) | v5>>12
|
||||
v1 += m[s[9]]
|
||||
v1 += v6
|
||||
v12 ^= v1
|
||||
v12 = v12<<(32-16) | v12>>16
|
||||
v11 += v12
|
||||
v6 ^= v11
|
||||
v6 = v6<<(32-12) | v6>>12
|
||||
v2 += m[s[10]]
|
||||
v2 += v7
|
||||
v13 ^= v2
|
||||
v13 = v13<<(32-16) | v13>>16
|
||||
v8 += v13
|
||||
v7 ^= v8
|
||||
v7 = v7<<(32-12) | v7>>12
|
||||
v3 += m[s[11]]
|
||||
v3 += v4
|
||||
v14 ^= v3
|
||||
v14 = v14<<(32-16) | v14>>16
|
||||
v9 += v14
|
||||
v4 ^= v9
|
||||
v4 = v4<<(32-12) | v4>>12
|
||||
|
||||
v0 += m[s[12]]
|
||||
v0 += v5
|
||||
v15 ^= v0
|
||||
v15 = v15<<(32-8) | v15>>8
|
||||
v10 += v15
|
||||
v5 ^= v10
|
||||
v5 = v5<<(32-7) | v5>>7
|
||||
v1 += m[s[13]]
|
||||
v1 += v6
|
||||
v12 ^= v1
|
||||
v12 = v12<<(32-8) | v12>>8
|
||||
v11 += v12
|
||||
v6 ^= v11
|
||||
v6 = v6<<(32-7) | v6>>7
|
||||
v2 += m[s[14]]
|
||||
v2 += v7
|
||||
v13 ^= v2
|
||||
v13 = v13<<(32-8) | v13>>8
|
||||
v8 += v13
|
||||
v7 ^= v8
|
||||
v7 = v7<<(32-7) | v7>>7
|
||||
v3 += m[s[15]]
|
||||
v3 += v4
|
||||
v14 ^= v3
|
||||
v14 = v14<<(32-8) | v14>>8
|
||||
v9 += v14
|
||||
v4 ^= v9
|
||||
v4 = v4<<(32-7) | v4>>7
|
||||
}
|
||||
|
||||
h[0] ^= v0 ^ v8
|
||||
h[1] ^= v1 ^ v9
|
||||
h[2] ^= v2 ^ v10
|
||||
h[3] ^= v3 ^ v11
|
||||
h[4] ^= v4 ^ v12
|
||||
h[5] ^= v5 ^ v13
|
||||
h[6] ^= v6 ^ v14
|
||||
h[7] ^= v7 ^ v15
|
||||
}
|
||||
c[0], c[1] = c0, c1
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// 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.
|
||||
|
||||
// +build !amd64,!386 gccgo appengine
|
||||
|
||||
package blake2s
|
||||
|
||||
var (
|
||||
useSSE4 = false
|
||||
useSSSE3 = false
|
||||
useSSE2 = false
|
||||
)
|
||||
|
||||
func hashBlocks(h *[8]uint32, c *[2]uint32, flag uint32, blocks []byte) {
|
||||
hashBlocksGeneric(h, c, flag, blocks)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package blake2s
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// XOF defines the interface to hash functions that
|
||||
// support arbitrary-length output.
|
||||
type XOF interface {
|
||||
// Write absorbs more data into the hash's state. It panics if called
|
||||
// after Read.
|
||||
io.Writer
|
||||
|
||||
// Read reads more output from the hash. It returns io.EOF if the limit
|
||||
// has been reached.
|
||||
io.Reader
|
||||
|
||||
// Clone returns a copy of the XOF in its current state.
|
||||
Clone() XOF
|
||||
|
||||
// Reset resets the XOF to its initial state.
|
||||
Reset()
|
||||
}
|
||||
|
||||
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
|
||||
// the the length of the output is not known in advance.
|
||||
const OutputLengthUnknown = 0
|
||||
|
||||
// magicUnknownOutputLength is a magic value for the output size that indicates
|
||||
// an unknown number of output bytes.
|
||||
const magicUnknownOutputLength = 65535
|
||||
|
||||
// maxOutputLength is the absolute maximum number of bytes to produce when the
|
||||
// number of output bytes is unknown.
|
||||
const maxOutputLength = (1 << 32) * 32
|
||||
|
||||
// NewXOF creates a new variable-output-length hash. The hash either produce a
|
||||
// known number of bytes (1 <= size < 65535), or an unknown number of bytes
|
||||
// (size == OutputLengthUnknown). In the latter case, an absolute limit of
|
||||
// 128GiB applies.
|
||||
//
|
||||
// A non-nil key turns the hash into a MAC. The key must between
|
||||
// zero and 32 bytes long.
|
||||
func NewXOF(size uint16, key []byte) (XOF, error) {
|
||||
if len(key) > Size {
|
||||
return nil, errKeySize
|
||||
}
|
||||
if size == magicUnknownOutputLength {
|
||||
// 2^16-1 indicates an unknown number of bytes and thus isn't a
|
||||
// valid length.
|
||||
return nil, errors.New("blake2s: XOF length too large")
|
||||
}
|
||||
if size == OutputLengthUnknown {
|
||||
size = magicUnknownOutputLength
|
||||
}
|
||||
x := &xof{
|
||||
d: digest{
|
||||
size: Size,
|
||||
keyLen: len(key),
|
||||
},
|
||||
length: size,
|
||||
}
|
||||
copy(x.d.key[:], key)
|
||||
x.Reset()
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type xof struct {
|
||||
d digest
|
||||
length uint16
|
||||
remaining uint64
|
||||
cfg, root, block [Size]byte
|
||||
offset int
|
||||
nodeOffset uint32
|
||||
readMode bool
|
||||
}
|
||||
|
||||
func (x *xof) Write(p []byte) (n int, err error) {
|
||||
if x.readMode {
|
||||
panic("blake2s: write to XOF after read")
|
||||
}
|
||||
return x.d.Write(p)
|
||||
}
|
||||
|
||||
func (x *xof) Clone() XOF {
|
||||
clone := *x
|
||||
return &clone
|
||||
}
|
||||
|
||||
func (x *xof) Reset() {
|
||||
x.cfg[0] = byte(Size)
|
||||
binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
|
||||
binary.LittleEndian.PutUint16(x.cfg[12:], x.length) // XOF length
|
||||
x.cfg[15] = byte(Size) // inner hash size
|
||||
|
||||
x.d.Reset()
|
||||
x.d.h[3] ^= uint32(x.length)
|
||||
|
||||
x.remaining = uint64(x.length)
|
||||
if x.remaining == magicUnknownOutputLength {
|
||||
x.remaining = maxOutputLength
|
||||
}
|
||||
x.offset, x.nodeOffset = 0, 0
|
||||
x.readMode = false
|
||||
}
|
||||
|
||||
func (x *xof) Read(p []byte) (n int, err error) {
|
||||
if !x.readMode {
|
||||
x.d.finalize(&x.root)
|
||||
x.readMode = true
|
||||
}
|
||||
|
||||
if x.remaining == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
n = len(p)
|
||||
if uint64(n) > x.remaining {
|
||||
n = int(x.remaining)
|
||||
p = p[:n]
|
||||
}
|
||||
|
||||
if x.offset > 0 {
|
||||
blockRemaining := Size - x.offset
|
||||
if n < blockRemaining {
|
||||
x.offset += copy(p, x.block[x.offset:])
|
||||
x.remaining -= uint64(n)
|
||||
return
|
||||
}
|
||||
copy(p, x.block[x.offset:])
|
||||
p = p[blockRemaining:]
|
||||
x.offset = 0
|
||||
x.remaining -= uint64(blockRemaining)
|
||||
}
|
||||
|
||||
for len(p) >= Size {
|
||||
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
|
||||
x.nodeOffset++
|
||||
|
||||
x.d.initConfig(&x.cfg)
|
||||
x.d.Write(x.root[:])
|
||||
x.d.finalize(&x.block)
|
||||
|
||||
copy(p, x.block[:])
|
||||
p = p[Size:]
|
||||
x.remaining -= uint64(Size)
|
||||
}
|
||||
|
||||
if todo := len(p); todo > 0 {
|
||||
if x.remaining < uint64(Size) {
|
||||
x.cfg[0] = byte(x.remaining)
|
||||
}
|
||||
binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
|
||||
x.nodeOffset++
|
||||
|
||||
x.d.initConfig(&x.cfg)
|
||||
x.d.Write(x.root[:])
|
||||
x.d.finalize(&x.block)
|
||||
|
||||
x.offset = copy(p, x.block[:todo])
|
||||
x.remaining -= uint64(todo)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *digest) initConfig(cfg *[Size]byte) {
|
||||
d.offset, d.c[0], d.c[1] = 0, 0, 0
|
||||
for i := range d.h {
|
||||
d.h[i] = iv[i] ^ binary.LittleEndian.Uint32(cfg[i*4:])
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.9
|
||||
|
||||
package blake2s
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
)
|
||||
|
||||
func init() {
|
||||
newHash256 := func() hash.Hash {
|
||||
h, _ := New256(nil)
|
||||
return h
|
||||
}
|
||||
|
||||
crypto.RegisterHash(crypto.BLAKE2s_256, newHash256)
|
||||
}
|
|
@ -12,7 +12,7 @@ type CryptTest struct {
|
|||
out []byte
|
||||
}
|
||||
|
||||
// Test vector values are from http://www.schneier.com/code/vectors.txt.
|
||||
// Test vector values are from https://www.schneier.com/code/vectors.txt.
|
||||
var encryptTests = []CryptTest{
|
||||
{
|
||||
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
package blowfish // import "golang.org/x/crypto/blowfish"
|
||||
|
||||
// The code is a port of Bruce Schneier's C implementation.
|
||||
// See http://www.schneier.com/blowfish.html.
|
||||
// See https://www.schneier.com/blowfish.html.
|
||||
|
||||
import "strconv"
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// The startup permutation array and substitution boxes.
|
||||
// They are the hexadecimal digits of PI; see:
|
||||
// http://www.schneier.com/code/constants.txt.
|
||||
// https://www.schneier.com/code/constants.txt.
|
||||
|
||||
package blowfish
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@ func bigFromBase10(s string) *big.Int {
|
|||
// u is the BN parameter that determines the prime: 1868033³.
|
||||
var u = bigFromBase10("6518589491078791937")
|
||||
|
||||
// p is a prime over which we form a basic field: 36u⁴+36u³+24u³+6u+1.
|
||||
// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
|
||||
var p = bigFromBase10("65000549695646603732796438742359905742825358107623003571877145026864184071783")
|
||||
|
||||
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u³+6u+1.
|
||||
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
|
||||
var Order = bigFromBase10("65000549695646603732796438742359905742570406053903786389881062969044166799969")
|
||||
|
||||
// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+3.
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
// 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 chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539.
|
||||
package chacha20poly1305 // import "golang.org/x/crypto/chacha20poly1305"
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
// KeySize is the size of the key used by this AEAD, in bytes.
|
||||
KeySize = 32
|
||||
// NonceSize is the size of the nonce used with this AEAD, in bytes.
|
||||
NonceSize = 12
|
||||
)
|
||||
|
||||
type chacha20poly1305 struct {
|
||||
key [32]byte
|
||||
}
|
||||
|
||||
// New returns a ChaCha20-Poly1305 AEAD that uses the given, 256-bit key.
|
||||
func New(key []byte) (cipher.AEAD, error) {
|
||||
if len(key) != KeySize {
|
||||
return nil, errors.New("chacha20poly1305: bad key length")
|
||||
}
|
||||
ret := new(chacha20poly1305)
|
||||
copy(ret.key[:], key)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) NonceSize() int {
|
||||
return NonceSize
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) Overhead() int {
|
||||
return 16
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if len(nonce) != NonceSize {
|
||||
panic("chacha20poly1305: bad nonce length passed to Seal")
|
||||
}
|
||||
|
||||
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||
panic("chacha20poly1305: plaintext too large")
|
||||
}
|
||||
|
||||
return c.seal(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
var errOpen = errors.New("chacha20poly1305: message authentication failed")
|
||||
|
||||
func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if len(nonce) != NonceSize {
|
||||
panic("chacha20poly1305: bad nonce length passed to Open")
|
||||
}
|
||||
if len(ciphertext) < 16 {
|
||||
return nil, errOpen
|
||||
}
|
||||
if uint64(len(ciphertext)) > (1<<38)-48 {
|
||||
panic("chacha20poly1305: ciphertext too large")
|
||||
}
|
||||
|
||||
return c.open(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
|
||||
// sliceForAppend takes a slice and a requested number of bytes. It returns a
|
||||
// slice with the contents of the given slice followed by that many bytes and a
|
||||
// second slice that aliases into it and contains only the extra bytes. If the
|
||||
// original slice has sufficient capacity then no allocation is performed.
|
||||
func sliceForAppend(in []byte, n int) (head, tail []byte) {
|
||||
if total := len(in) + n; cap(in) >= total {
|
||||
head = in[:total]
|
||||
} else {
|
||||
head = make([]byte, total)
|
||||
copy(head, in)
|
||||
}
|
||||
tail = head[len(in):]
|
||||
return
|
||||
}
|
127
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
Normal file
127
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
generated
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
// 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.
|
||||
|
||||
// +build go1.7,amd64,!gccgo,!appengine
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
||||
|
||||
// cpuid is implemented in chacha20poly1305_amd64.s.
|
||||
func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
|
||||
|
||||
// xgetbv with ecx = 0 is implemented in chacha20poly1305_amd64.s.
|
||||
func xgetbv() (eax, edx uint32)
|
||||
|
||||
var (
|
||||
useASM bool
|
||||
useAVX2 bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
detectCPUFeatures()
|
||||
}
|
||||
|
||||
// detectCPUFeatures is used to detect if cpu instructions
|
||||
// used by the functions implemented in assembler in
|
||||
// chacha20poly1305_amd64.s are supported.
|
||||
func detectCPUFeatures() {
|
||||
maxID, _, _, _ := cpuid(0, 0)
|
||||
if maxID < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
_, _, ecx1, _ := cpuid(1, 0)
|
||||
|
||||
haveSSSE3 := isSet(9, ecx1)
|
||||
useASM = haveSSSE3
|
||||
|
||||
haveOSXSAVE := isSet(27, ecx1)
|
||||
|
||||
osSupportsAVX := false
|
||||
// For XGETBV, OSXSAVE bit is required and sufficient.
|
||||
if haveOSXSAVE {
|
||||
eax, _ := xgetbv()
|
||||
// Check if XMM and YMM registers have OS support.
|
||||
osSupportsAVX = isSet(1, eax) && isSet(2, eax)
|
||||
}
|
||||
haveAVX := isSet(28, ecx1) && osSupportsAVX
|
||||
|
||||
if maxID < 7 {
|
||||
return
|
||||
}
|
||||
|
||||
_, ebx7, _, _ := cpuid(7, 0)
|
||||
haveAVX2 := isSet(5, ebx7) && haveAVX
|
||||
haveBMI2 := isSet(8, ebx7)
|
||||
|
||||
useAVX2 = haveAVX2 && haveBMI2
|
||||
}
|
||||
|
||||
// isSet checks if bit at bitpos is set in value.
|
||||
func isSet(bitpos uint, value uint32) bool {
|
||||
return value&(1<<bitpos) != 0
|
||||
}
|
||||
|
||||
// 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) {
|
||||
state[0] = 0x61707865
|
||||
state[1] = 0x3320646e
|
||||
state[2] = 0x79622d32
|
||||
state[3] = 0x6b206574
|
||||
|
||||
state[4] = binary.LittleEndian.Uint32(key[: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[12] = 0
|
||||
state[13] = binary.LittleEndian.Uint32(nonce[:4])
|
||||
state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||
state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if !useASM {
|
||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
var state [16]uint32
|
||||
setupState(&state, &c.key, nonce)
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
||||
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if !useASM {
|
||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||
}
|
||||
|
||||
var state [16]uint32
|
||||
setupState(&state, &c.key, nonce)
|
||||
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
return nil, errOpen
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
2714
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
Normal file
2714
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
70
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
Normal file
70
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
// 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 chacha20poly1305
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"golang.org/x/crypto/chacha20poly1305/internal/chacha20"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
)
|
||||
|
||||
func roundTo16(n int) int {
|
||||
return 16 * ((n + 15) / 16)
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
var counter [16]byte
|
||||
copy(counter[4:], nonce)
|
||||
|
||||
var polyKey [32]byte
|
||||
chacha20.XORKeyStream(polyKey[:], polyKey[:], &counter, &c.key)
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
|
||||
counter[0] = 1
|
||||
chacha20.XORKeyStream(out, plaintext, &counter, &c.key)
|
||||
|
||||
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) {
|
||||
var tag [poly1305.TagSize]byte
|
||||
copy(tag[:], ciphertext[len(ciphertext)-16:])
|
||||
ciphertext = ciphertext[:len(ciphertext)-16]
|
||||
|
||||
var counter [16]byte
|
||||
copy(counter[4:], nonce)
|
||||
|
||||
var polyKey [32]byte
|
||||
chacha20.XORKeyStream(polyKey[:], polyKey[:], &counter, &c.key)
|
||||
|
||||
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 !poly1305.Verify(&tag, polyInput, &polyKey) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
return nil, errOpen
|
||||
}
|
||||
|
||||
counter[0] = 1
|
||||
chacha20.XORKeyStream(out, ciphertext, &counter, &c.key)
|
||||
return ret, nil
|
||||
}
|
15
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
generated
vendored
Normal file
15
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
// 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.
|
||||
|
||||
// +build !amd64 !go1.7 gccgo appengine
|
||||
|
||||
package chacha20poly1305
|
||||
|
||||
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
||||
}
|
||||
|
||||
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
||||
}
|
182
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
generated
vendored
Normal file
182
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
generated
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
// 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 chacha20poly1305
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
cr "crypto/rand"
|
||||
"encoding/hex"
|
||||
mr "math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestVectors(t *testing.T) {
|
||||
for i, test := range chacha20Poly1305Tests {
|
||||
key, _ := hex.DecodeString(test.key)
|
||||
nonce, _ := hex.DecodeString(test.nonce)
|
||||
ad, _ := hex.DecodeString(test.aad)
|
||||
plaintext, _ := hex.DecodeString(test.plaintext)
|
||||
|
||||
aead, err := New(key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ct := aead.Seal(nil, nonce, plaintext, ad)
|
||||
if ctHex := hex.EncodeToString(ct); ctHex != test.out {
|
||||
t.Errorf("#%d: got %s, want %s", i, ctHex, test.out)
|
||||
continue
|
||||
}
|
||||
|
||||
plaintext2, err := aead.Open(nil, nonce, ct, ad)
|
||||
if err != nil {
|
||||
t.Errorf("#%d: Open failed", i)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(plaintext, plaintext2) {
|
||||
t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(ad) > 0 {
|
||||
alterAdIdx := mr.Intn(len(ad))
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering additional data", i)
|
||||
}
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
}
|
||||
|
||||
alterNonceIdx := mr.Intn(aead.NonceSize())
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering nonce", i)
|
||||
}
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
|
||||
alterCtIdx := mr.Intn(len(ct))
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
|
||||
t.Errorf("#%d: Open was successful after altering ciphertext", i)
|
||||
}
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandom(t *testing.T) {
|
||||
// Some random tests to verify Open(Seal) == Plaintext
|
||||
for i := 0; i < 256; i++ {
|
||||
var nonce [12]byte
|
||||
var key [32]byte
|
||||
|
||||
al := mr.Intn(128)
|
||||
pl := mr.Intn(16384)
|
||||
ad := make([]byte, al)
|
||||
plaintext := make([]byte, pl)
|
||||
cr.Read(key[:])
|
||||
cr.Read(nonce[:])
|
||||
cr.Read(ad)
|
||||
cr.Read(plaintext)
|
||||
|
||||
aead, err := New(key[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ct := aead.Seal(nil, nonce[:], plaintext, ad)
|
||||
|
||||
plaintext2, err := aead.Open(nil, nonce[:], ct, ad)
|
||||
if err != nil {
|
||||
t.Errorf("Random #%d: Open failed", i)
|
||||
continue
|
||||
}
|
||||
|
||||
if !bytes.Equal(plaintext, plaintext2) {
|
||||
t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(ad) > 0 {
|
||||
alterAdIdx := mr.Intn(len(ad))
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering additional data", i)
|
||||
}
|
||||
ad[alterAdIdx] ^= 0x80
|
||||
}
|
||||
|
||||
alterNonceIdx := mr.Intn(aead.NonceSize())
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering nonce", i)
|
||||
}
|
||||
nonce[alterNonceIdx] ^= 0x80
|
||||
|
||||
alterCtIdx := mr.Intn(len(ct))
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
|
||||
t.Errorf("Random #%d: Open was successful after altering ciphertext", i)
|
||||
}
|
||||
ct[alterCtIdx] ^= 0x80
|
||||
}
|
||||
}
|
||||
|
||||
func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte) {
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [32]byte
|
||||
var nonce [12]byte
|
||||
var ad [13]byte
|
||||
var out []byte
|
||||
|
||||
aead, _ := New(key[:])
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
out = aead.Seal(out[:0], nonce[:], buf[:], ad[:])
|
||||
}
|
||||
}
|
||||
|
||||
func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) {
|
||||
b.SetBytes(int64(len(buf)))
|
||||
|
||||
var key [32]byte
|
||||
var nonce [12]byte
|
||||
var ad [13]byte
|
||||
var ct []byte
|
||||
var out []byte
|
||||
|
||||
aead, _ := New(key[:])
|
||||
ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:])
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
out, _ = aead.Open(out[:0], nonce[:], ct[:], ad[:])
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Open_64(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Open(b, make([]byte, 64))
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Seal_64(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Seal(b, make([]byte, 64))
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Open_1350(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Open(b, make([]byte, 1350))
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Seal_1350(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Seal(b, make([]byte, 1350))
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Open_8K(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Open(b, make([]byte, 8*1024))
|
||||
}
|
||||
|
||||
func BenchmarkChacha20Poly1305Seal_8K(b *testing.B) {
|
||||
benchamarkChaCha20Poly1305Seal(b, make([]byte, 8*1024))
|
||||
}
|
332
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go
generated
vendored
Normal file
332
vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_vectors_test.go
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
199
vendor/golang.org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go
generated
vendored
Normal file
199
vendor/golang.org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go
generated
vendored
Normal file
|
@ -0,0 +1,199 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ChaCha20 implements the core ChaCha20 function as specified in https://tools.ietf.org/html/rfc7539#section-2.3.
|
||||
package chacha20
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
const rounds = 20
|
||||
|
||||
// core applies the ChaCha20 core function to 16-byte input in, 32-byte key k,
|
||||
// and 16-byte constant c, and puts the result into 64-byte array out.
|
||||
func core(out *[64]byte, in *[16]byte, k *[32]byte) {
|
||||
j0 := uint32(0x61707865)
|
||||
j1 := uint32(0x3320646e)
|
||||
j2 := uint32(0x79622d32)
|
||||
j3 := uint32(0x6b206574)
|
||||
j4 := binary.LittleEndian.Uint32(k[0:4])
|
||||
j5 := binary.LittleEndian.Uint32(k[4:8])
|
||||
j6 := binary.LittleEndian.Uint32(k[8:12])
|
||||
j7 := binary.LittleEndian.Uint32(k[12:16])
|
||||
j8 := binary.LittleEndian.Uint32(k[16:20])
|
||||
j9 := binary.LittleEndian.Uint32(k[20:24])
|
||||
j10 := binary.LittleEndian.Uint32(k[24:28])
|
||||
j11 := binary.LittleEndian.Uint32(k[28:32])
|
||||
j12 := binary.LittleEndian.Uint32(in[0:4])
|
||||
j13 := binary.LittleEndian.Uint32(in[4:8])
|
||||
j14 := binary.LittleEndian.Uint32(in[8:12])
|
||||
j15 := binary.LittleEndian.Uint32(in[12:16])
|
||||
|
||||
x0, x1, x2, x3, x4, x5, x6, x7 := j0, j1, j2, j3, j4, j5, j6, j7
|
||||
x8, x9, x10, x11, x12, x13, x14, x15 := j8, j9, j10, j11, j12, j13, j14, j15
|
||||
|
||||
for i := 0; i < rounds; i += 2 {
|
||||
x0 += x4
|
||||
x12 ^= x0
|
||||
x12 = (x12 << 16) | (x12 >> (16))
|
||||
x8 += x12
|
||||
x4 ^= x8
|
||||
x4 = (x4 << 12) | (x4 >> (20))
|
||||
x0 += x4
|
||||
x12 ^= x0
|
||||
x12 = (x12 << 8) | (x12 >> (24))
|
||||
x8 += x12
|
||||
x4 ^= x8
|
||||
x4 = (x4 << 7) | (x4 >> (25))
|
||||
x1 += x5
|
||||
x13 ^= x1
|
||||
x13 = (x13 << 16) | (x13 >> 16)
|
||||
x9 += x13
|
||||
x5 ^= x9
|
||||
x5 = (x5 << 12) | (x5 >> 20)
|
||||
x1 += x5
|
||||
x13 ^= x1
|
||||
x13 = (x13 << 8) | (x13 >> 24)
|
||||
x9 += x13
|
||||
x5 ^= x9
|
||||
x5 = (x5 << 7) | (x5 >> 25)
|
||||
x2 += x6
|
||||
x14 ^= x2
|
||||
x14 = (x14 << 16) | (x14 >> 16)
|
||||
x10 += x14
|
||||
x6 ^= x10
|
||||
x6 = (x6 << 12) | (x6 >> 20)
|
||||
x2 += x6
|
||||
x14 ^= x2
|
||||
x14 = (x14 << 8) | (x14 >> 24)
|
||||
x10 += x14
|
||||
x6 ^= x10
|
||||
x6 = (x6 << 7) | (x6 >> 25)
|
||||
x3 += x7
|
||||
x15 ^= x3
|
||||
x15 = (x15 << 16) | (x15 >> 16)
|
||||
x11 += x15
|
||||
x7 ^= x11
|
||||
x7 = (x7 << 12) | (x7 >> 20)
|
||||
x3 += x7
|
||||
x15 ^= x3
|
||||
x15 = (x15 << 8) | (x15 >> 24)
|
||||
x11 += x15
|
||||
x7 ^= x11
|
||||
x7 = (x7 << 7) | (x7 >> 25)
|
||||
x0 += x5
|
||||
x15 ^= x0
|
||||
x15 = (x15 << 16) | (x15 >> 16)
|
||||
x10 += x15
|
||||
x5 ^= x10
|
||||
x5 = (x5 << 12) | (x5 >> 20)
|
||||
x0 += x5
|
||||
x15 ^= x0
|
||||
x15 = (x15 << 8) | (x15 >> 24)
|
||||
x10 += x15
|
||||
x5 ^= x10
|
||||
x5 = (x5 << 7) | (x5 >> 25)
|
||||
x1 += x6
|
||||
x12 ^= x1
|
||||
x12 = (x12 << 16) | (x12 >> 16)
|
||||
x11 += x12
|
||||
x6 ^= x11
|
||||
x6 = (x6 << 12) | (x6 >> 20)
|
||||
x1 += x6
|
||||
x12 ^= x1
|
||||
x12 = (x12 << 8) | (x12 >> 24)
|
||||
x11 += x12
|
||||
x6 ^= x11
|
||||
x6 = (x6 << 7) | (x6 >> 25)
|
||||
x2 += x7
|
||||
x13 ^= x2
|
||||
x13 = (x13 << 16) | (x13 >> 16)
|
||||
x8 += x13
|
||||
x7 ^= x8
|
||||
x7 = (x7 << 12) | (x7 >> 20)
|
||||
x2 += x7
|
||||
x13 ^= x2
|
||||
x13 = (x13 << 8) | (x13 >> 24)
|
||||
x8 += x13
|
||||
x7 ^= x8
|
||||
x7 = (x7 << 7) | (x7 >> 25)
|
||||
x3 += x4
|
||||
x14 ^= x3
|
||||
x14 = (x14 << 16) | (x14 >> 16)
|
||||
x9 += x14
|
||||
x4 ^= x9
|
||||
x4 = (x4 << 12) | (x4 >> 20)
|
||||
x3 += x4
|
||||
x14 ^= x3
|
||||
x14 = (x14 << 8) | (x14 >> 24)
|
||||
x9 += x14
|
||||
x4 ^= x9
|
||||
x4 = (x4 << 7) | (x4 >> 25)
|
||||
}
|
||||
|
||||
x0 += j0
|
||||
x1 += j1
|
||||
x2 += j2
|
||||
x3 += j3
|
||||
x4 += j4
|
||||
x5 += j5
|
||||
x6 += j6
|
||||
x7 += j7
|
||||
x8 += j8
|
||||
x9 += j9
|
||||
x10 += j10
|
||||
x11 += j11
|
||||
x12 += j12
|
||||
x13 += j13
|
||||
x14 += j14
|
||||
x15 += j15
|
||||
|
||||
binary.LittleEndian.PutUint32(out[0:4], x0)
|
||||
binary.LittleEndian.PutUint32(out[4:8], x1)
|
||||
binary.LittleEndian.PutUint32(out[8:12], x2)
|
||||
binary.LittleEndian.PutUint32(out[12:16], x3)
|
||||
binary.LittleEndian.PutUint32(out[16:20], x4)
|
||||
binary.LittleEndian.PutUint32(out[20:24], x5)
|
||||
binary.LittleEndian.PutUint32(out[24:28], x6)
|
||||
binary.LittleEndian.PutUint32(out[28:32], x7)
|
||||
binary.LittleEndian.PutUint32(out[32:36], x8)
|
||||
binary.LittleEndian.PutUint32(out[36:40], x9)
|
||||
binary.LittleEndian.PutUint32(out[40:44], x10)
|
||||
binary.LittleEndian.PutUint32(out[44:48], x11)
|
||||
binary.LittleEndian.PutUint32(out[48:52], x12)
|
||||
binary.LittleEndian.PutUint32(out[52:56], x13)
|
||||
binary.LittleEndian.PutUint32(out[56:60], x14)
|
||||
binary.LittleEndian.PutUint32(out[60:64], x15)
|
||||
}
|
||||
|
||||
// XORKeyStream crypts bytes from in to out using the given key and counters.
|
||||
// In and out may be the same slice but otherwise should not overlap. Counter
|
||||
// contains the raw ChaCha20 counter bytes (i.e. block counter followed by
|
||||
// nonce).
|
||||
func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
|
||||
var block [64]byte
|
||||
var counterCopy [16]byte
|
||||
copy(counterCopy[:], counter[:])
|
||||
|
||||
for len(in) >= 64 {
|
||||
core(&block, &counterCopy, key)
|
||||
for i, x := range block {
|
||||
out[i] = in[i] ^ x
|
||||
}
|
||||
u := uint32(1)
|
||||
for i := 0; i < 4; i++ {
|
||||
u += uint32(counterCopy[i])
|
||||
counterCopy[i] = byte(u)
|
||||
u >>= 8
|
||||
}
|
||||
in = in[64:]
|
||||
out = out[64:]
|
||||
}
|
||||
|
||||
if len(in) > 0 {
|
||||
core(&block, &counterCopy, key)
|
||||
for i, v := range in {
|
||||
out[i] = v ^ block[i]
|
||||
}
|
||||
}
|
||||
}
|
33
vendor/golang.org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
generated
vendored
Normal file
33
vendor/golang.org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package chacha20
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCore(t *testing.T) {
|
||||
// This is just a smoke test that checks the example from
|
||||
// https://tools.ietf.org/html/rfc7539#section-2.3.2. The
|
||||
// chacha20poly1305 package contains much more extensive tests of this
|
||||
// code.
|
||||
var key [32]byte
|
||||
for i := range key {
|
||||
key[i] = byte(i)
|
||||
}
|
||||
|
||||
var input [16]byte
|
||||
input[0] = 1
|
||||
input[7] = 9
|
||||
input[11] = 0x4a
|
||||
|
||||
var out [64]byte
|
||||
XORKeyStream(out[:], out[:], &input, &key)
|
||||
const expected = "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
|
||||
if result := hex.EncodeToString(out[:]); result != expected {
|
||||
t.Errorf("wanted %x but got %x", expected, result)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,604 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cryptobyte
|
||||
|
||||
import (
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This file contains ASN.1-related methods for String and Builder.
|
||||
|
||||
// Tag represents an ASN.1 tag number and class (together also referred to as
|
||||
// identifier octets). Methods in this package only support the low-tag-number
|
||||
// form, i.e. a single identifier octet with bits 7-8 encoding the class and
|
||||
// bits 1-6 encoding the tag number.
|
||||
type Tag uint8
|
||||
|
||||
// Contructed returns t with the context-specific class bit set.
|
||||
func (t Tag) ContextSpecific() Tag { return t | 0x80 }
|
||||
|
||||
// Contructed returns t with the constructed class bit set.
|
||||
func (t Tag) Constructed() Tag { return t | 0x20 }
|
||||
|
||||
// Builder
|
||||
|
||||
// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1Int64(v int64) {
|
||||
b.addASN1Signed(asn1.TagInteger, v)
|
||||
}
|
||||
|
||||
// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
|
||||
func (b *Builder) AddASN1Enum(v int64) {
|
||||
b.addASN1Signed(asn1.TagEnum, v)
|
||||
}
|
||||
|
||||
func (b *Builder) addASN1Signed(tag Tag, v int64) {
|
||||
b.AddASN1(tag, func(c *Builder) {
|
||||
length := 1
|
||||
for i := v; i >= 0x80 || i < -0x80; i >>= 8 {
|
||||
length++
|
||||
}
|
||||
|
||||
for ; length > 0; length-- {
|
||||
i := v >> uint((length-1)*8) & 0xff
|
||||
c.AddUint8(uint8(i))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1Uint64(v uint64) {
|
||||
b.AddASN1(asn1.TagInteger, func(c *Builder) {
|
||||
length := 1
|
||||
for i := v; i >= 0x80; i >>= 8 {
|
||||
length++
|
||||
}
|
||||
|
||||
for ; length > 0; length-- {
|
||||
i := v >> uint((length-1)*8) & 0xff
|
||||
c.AddUint8(uint8(i))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1BigInt(n *big.Int) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b.AddASN1(asn1.TagInteger, func(c *Builder) {
|
||||
if n.Sign() < 0 {
|
||||
// A negative number has to be converted to two's-complement form. So we
|
||||
// invert and subtract 1. If the most-significant-bit isn't set then
|
||||
// we'll need to pad the beginning with 0xff in order to keep the number
|
||||
// negative.
|
||||
nMinus1 := new(big.Int).Neg(n)
|
||||
nMinus1.Sub(nMinus1, bigOne)
|
||||
bytes := nMinus1.Bytes()
|
||||
for i := range bytes {
|
||||
bytes[i] ^= 0xff
|
||||
}
|
||||
if bytes[0]&0x80 == 0 {
|
||||
c.add(0xff)
|
||||
}
|
||||
c.add(bytes...)
|
||||
} else if n.Sign() == 0 {
|
||||
c.add(0)
|
||||
} else {
|
||||
bytes := n.Bytes()
|
||||
if bytes[0]&0x80 != 0 {
|
||||
c.add(0)
|
||||
}
|
||||
c.add(bytes...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING.
|
||||
func (b *Builder) AddASN1OctetString(bytes []byte) {
|
||||
b.AddASN1(asn1.TagOctetString, func(c *Builder) {
|
||||
c.AddBytes(bytes)
|
||||
})
|
||||
}
|
||||
|
||||
const generalizedTimeFormatStr = "20060102150405Z0700"
|
||||
|
||||
// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME.
|
||||
func (b *Builder) AddASN1GeneralizedTime(t time.Time) {
|
||||
if t.Year() < 0 || t.Year() > 9999 {
|
||||
b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t)
|
||||
return
|
||||
}
|
||||
b.AddASN1(asn1.TagGeneralizedTime, func(c *Builder) {
|
||||
c.AddBytes([]byte(t.Format(generalizedTimeFormatStr)))
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING.
|
||||
func (b *Builder) AddASN1BitString(s asn1.BitString) {
|
||||
// TODO(martinkr): Implement.
|
||||
b.MarshalASN1(s)
|
||||
}
|
||||
|
||||
// MarshalASN1 calls asn1.Marshal on its input and appends the result if
|
||||
// successful or records an error if one occurred.
|
||||
func (b *Builder) MarshalASN1(v interface{}) {
|
||||
// NOTE(martinkr): This is somewhat of a hack to allow propagation of
|
||||
// asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a
|
||||
// value embedded into a struct, its tag information is lost.
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
bytes, err := asn1.Marshal(v)
|
||||
if err != nil {
|
||||
b.err = err
|
||||
return
|
||||
}
|
||||
b.AddBytes(bytes)
|
||||
}
|
||||
|
||||
// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag.
|
||||
// Tags greater than 30 are not supported and result in an error (i.e.
|
||||
// low-tag-number form only). The child builder passed to the
|
||||
// BuilderContinuation can be used to build the content of the ASN.1 object.
|
||||
func (b *Builder) AddASN1(tag Tag, f BuilderContinuation) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
// Identifiers with the low five bits set indicate high-tag-number format
|
||||
// (two or more octets), which we don't support.
|
||||
if tag&0x1f == 0x1f {
|
||||
b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag)
|
||||
return
|
||||
}
|
||||
b.AddUint8(uint8(tag))
|
||||
b.addLengthPrefixed(1, true, f)
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
|
||||
|
||||
// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does
|
||||
// not point to an integer or to a big.Int, it panics. It returns true on
|
||||
// success and false on error.
|
||||
func (s *String) ReadASN1Integer(out interface{}) bool {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
panic("out is not a pointer")
|
||||
}
|
||||
switch reflect.ValueOf(out).Elem().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
var i int64
|
||||
if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) {
|
||||
return false
|
||||
}
|
||||
reflect.ValueOf(out).Elem().SetInt(i)
|
||||
return true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
var u uint64
|
||||
if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) {
|
||||
return false
|
||||
}
|
||||
reflect.ValueOf(out).Elem().SetUint(u)
|
||||
return true
|
||||
case reflect.Struct:
|
||||
if reflect.TypeOf(out).Elem() == bigIntType {
|
||||
return s.readASN1BigInt(out.(*big.Int))
|
||||
}
|
||||
}
|
||||
panic("out does not point to an integer type")
|
||||
}
|
||||
|
||||
func checkASN1Integer(bytes []byte) bool {
|
||||
if len(bytes) == 0 {
|
||||
// An INTEGER is encoded with at least one octet.
|
||||
return false
|
||||
}
|
||||
if len(bytes) == 1 {
|
||||
return true
|
||||
}
|
||||
if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 {
|
||||
// Value is not minimally encoded.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var bigOne = big.NewInt(1)
|
||||
|
||||
func (s *String) readASN1BigInt(out *big.Int) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) {
|
||||
return false
|
||||
}
|
||||
if bytes[0]&0x80 == 0x80 {
|
||||
// Negative number.
|
||||
neg := make([]byte, len(bytes))
|
||||
for i, b := range bytes {
|
||||
neg[i] = ^b
|
||||
}
|
||||
out.SetBytes(neg)
|
||||
out.Add(out, bigOne)
|
||||
out.Neg(out)
|
||||
} else {
|
||||
out.SetBytes(bytes)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readASN1Int64(out *int64) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func asn1Signed(out *int64, n []byte) bool {
|
||||
length := len(n)
|
||||
if length > 8 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
*out <<= 8
|
||||
*out |= int64(n[i])
|
||||
}
|
||||
// Shift up and down in order to sign extend the result.
|
||||
*out <<= 64 - uint8(length)*8
|
||||
*out >>= 64 - uint8(length)*8
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readASN1Uint64(out *uint64) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func asn1Unsigned(out *uint64, n []byte) bool {
|
||||
length := len(n)
|
||||
if length > 9 || length == 9 && n[0] != 0 {
|
||||
// Too large for uint64.
|
||||
return false
|
||||
}
|
||||
if n[0]&0x80 != 0 {
|
||||
// Negative number.
|
||||
return false
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
*out <<= 8
|
||||
*out |= uint64(n[i])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns
|
||||
// true on success and false on error.
|
||||
func (s *String) ReadASN1Enum(out *int) bool {
|
||||
var bytes String
|
||||
var i int64
|
||||
if !s.ReadASN1(&bytes, asn1.TagEnum) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) {
|
||||
return false
|
||||
}
|
||||
if int64(int(i)) != i {
|
||||
return false
|
||||
}
|
||||
*out = int(i)
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readBase128Int(out *int) bool {
|
||||
ret := 0
|
||||
for i := 0; len(*s) > 0; i++ {
|
||||
if i == 4 {
|
||||
return false
|
||||
}
|
||||
ret <<= 7
|
||||
b := s.read(1)[0]
|
||||
ret |= int(b & 0x7f)
|
||||
if b&0x80 == 0 {
|
||||
*out = ret
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false // truncated
|
||||
}
|
||||
|
||||
// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
|
||||
// advances. It returns true on success and false on error.
|
||||
func (s *String) ReadASN1ObjectIdentifier(out *asn1.ObjectIdentifier) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagOID) || len(bytes) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// In the worst case, we get two elements from the first byte (which is
|
||||
// encoded differently) and then every varint is a single byte long.
|
||||
components := make([]int, len(bytes)+1)
|
||||
|
||||
// The first varint is 40*value1 + value2:
|
||||
// According to this packing, value1 can take the values 0, 1 and 2 only.
|
||||
// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
|
||||
// then there are no restrictions on value2.
|
||||
var v int
|
||||
if !bytes.readBase128Int(&v) {
|
||||
return false
|
||||
}
|
||||
if v < 80 {
|
||||
components[0] = v / 40
|
||||
components[1] = v % 40
|
||||
} else {
|
||||
components[0] = 2
|
||||
components[1] = v - 80
|
||||
}
|
||||
|
||||
i := 2
|
||||
for ; len(bytes) > 0; i++ {
|
||||
if !bytes.readBase128Int(&v) {
|
||||
return false
|
||||
}
|
||||
components[i] = v
|
||||
}
|
||||
*out = components[:i]
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
|
||||
// advances. It returns true on success and false on error.
|
||||
func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagGeneralizedTime) {
|
||||
return false
|
||||
}
|
||||
t := string(bytes)
|
||||
res, err := time.Parse(generalizedTimeFormatStr, t)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if serialized := res.Format(generalizedTimeFormatStr); serialized != t {
|
||||
return false
|
||||
}
|
||||
*out = res
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It
|
||||
// returns true on success and false on error.
|
||||
func (s *String) ReadASN1BitString(out *asn1.BitString) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagBitString) || len(bytes) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
paddingBits := uint8(bytes[0])
|
||||
bytes = bytes[1:]
|
||||
if paddingBits > 7 ||
|
||||
len(bytes) == 0 && paddingBits != 0 ||
|
||||
len(bytes) > 0 && bytes[len(bytes)-1]&(1<<paddingBits-1) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
out.BitLength = len(bytes)*8 - int(paddingBits)
|
||||
out.Bytes = bytes
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
func (s *String) ReadASN1Bytes(out *[]byte, tag Tag) bool {
|
||||
return s.ReadASN1((*String)(out), tag)
|
||||
}
|
||||
|
||||
// ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadASN1(out *String, tag Tag) bool {
|
||||
var t Tag
|
||||
if !s.ReadAnyASN1(out, &t) || t != tag {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadASN1Element(out *String, tag Tag) bool {
|
||||
var t Tag
|
||||
if !s.ReadAnyASN1Element(out, &t) || t != tag {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, sets outTag to its tag, and advances. It
|
||||
// returns true on success and false on error.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadAnyASN1(out *String, outTag *Tag) bool {
|
||||
return s.readASN1(out, outTag, true /* skip header */)
|
||||
}
|
||||
|
||||
// ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element
|
||||
// (including tag and length bytes) into out, sets outTag to is tag, and
|
||||
// advances. It returns true on success and false on error.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadAnyASN1Element(out *String, outTag *Tag) bool {
|
||||
return s.readASN1(out, outTag, false /* include header */)
|
||||
}
|
||||
|
||||
// PeekASN1Tag returns true if the next ASN.1 value on the string starts with
|
||||
// the given tag.
|
||||
func (s String) PeekASN1Tag(tag Tag) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
return Tag(s[0]) == tag
|
||||
}
|
||||
|
||||
// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.Element
|
||||
// (not including tag and length bytes) tagged with the given tag into out. It
|
||||
// stores whether an element with the tag was found in outPresent, unless
|
||||
// outPresent is nil. It returns true on success and false on error.
|
||||
func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag Tag) bool {
|
||||
present := s.PeekASN1Tag(tag)
|
||||
if outPresent != nil {
|
||||
*outPresent = present
|
||||
}
|
||||
if present && !s.ReadASN1(out, tag) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER
|
||||
// explicitly tagged with tag into out and advances. If no element with a
|
||||
// matching tag is present, it writes defaultValue into out instead. If out
|
||||
// does not point to an integer or to a big.Int, it panics. It returns true on
|
||||
// success and false on error.
|
||||
func (s *String) ReadOptionalASN1Integer(out interface{}, tag Tag, defaultValue interface{}) bool {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
panic("out is not a pointer")
|
||||
}
|
||||
var present bool
|
||||
var i String
|
||||
if !s.ReadOptionalASN1(&i, &present, tag) {
|
||||
return false
|
||||
}
|
||||
if !present {
|
||||
switch reflect.ValueOf(out).Elem().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(defaultValue))
|
||||
case reflect.Struct:
|
||||
if reflect.TypeOf(out).Elem() != bigIntType {
|
||||
panic("invalid integer type")
|
||||
}
|
||||
if reflect.TypeOf(defaultValue).Kind() != reflect.Ptr ||
|
||||
reflect.TypeOf(defaultValue).Elem() != bigIntType {
|
||||
panic("out points to big.Int, but defaultValue does not")
|
||||
}
|
||||
out.(*big.Int).Set(defaultValue.(*big.Int))
|
||||
default:
|
||||
panic("invalid integer type")
|
||||
}
|
||||
return true
|
||||
}
|
||||
if !i.ReadASN1Integer(out) || !i.Empty() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING
|
||||
// explicitly tagged with tag into out and advances. If no element with a
|
||||
// matching tag is present, it writes defaultValue into out instead. It returns
|
||||
// true on success and false on error.
|
||||
func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag Tag) bool {
|
||||
var present bool
|
||||
var child String
|
||||
if !s.ReadOptionalASN1(&child, &present, tag) {
|
||||
return false
|
||||
}
|
||||
if outPresent != nil {
|
||||
*outPresent = present
|
||||
}
|
||||
if present {
|
||||
var oct String
|
||||
if !child.ReadASN1(&oct, asn1.TagOctetString) || !child.Empty() {
|
||||
return false
|
||||
}
|
||||
*out = oct
|
||||
} else {
|
||||
*out = nil
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readASN1(out *String, outTag *Tag, skipHeader bool) bool {
|
||||
if len(*s) < 2 {
|
||||
return false
|
||||
}
|
||||
tag, lenByte := (*s)[0], (*s)[1]
|
||||
|
||||
if tag&0x1f == 0x1f {
|
||||
// ITU-T X.690 section 8.1.2
|
||||
//
|
||||
// An identifier octet with a tag part of 0x1f indicates a high-tag-number
|
||||
// form identifier with two or more octets. We only support tags less than
|
||||
// 31 (i.e. low-tag-number form, single octet identifier).
|
||||
return false
|
||||
}
|
||||
|
||||
if outTag != nil {
|
||||
*outTag = Tag(tag)
|
||||
}
|
||||
|
||||
// ITU-T X.690 section 8.1.3
|
||||
//
|
||||
// Bit 8 of the first length byte indicates whether the length is short- or
|
||||
// long-form.
|
||||
var length, headerLen uint32 // length includes headerLen
|
||||
if lenByte&0x80 == 0 {
|
||||
// Short-form length (section 8.1.3.4), encoded in bits 1-7.
|
||||
length = uint32(lenByte) + 2
|
||||
headerLen = 2
|
||||
} else {
|
||||
// Long-form length (section 8.1.3.5). Bits 1-7 encode the number of octets
|
||||
// used to encode the length.
|
||||
lenLen := lenByte & 0x7f
|
||||
var len32 uint32
|
||||
|
||||
if lenLen == 0 || lenLen > 4 || len(*s) < int(2+lenLen) {
|
||||
return false
|
||||
}
|
||||
|
||||
lenBytes := String((*s)[2 : 2+lenLen])
|
||||
if !lenBytes.readUnsigned(&len32, int(lenLen)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
|
||||
// with the minimum number of octets.
|
||||
if len32 < 128 {
|
||||
// Length should have used short-form encoding.
|
||||
return false
|
||||
}
|
||||
if len32>>((lenLen-1)*8) == 0 {
|
||||
// Leading octet is 0. Length should have been at least one byte shorter.
|
||||
return false
|
||||
}
|
||||
|
||||
headerLen = 2 + uint32(lenLen)
|
||||
if headerLen+len32 < len32 {
|
||||
// Overflow.
|
||||
return false
|
||||
}
|
||||
length = headerLen + len32
|
||||
}
|
||||
|
||||
if uint32(int(length)) != length || !s.ReadBytes((*[]byte)(out), int(length)) {
|
||||
return false
|
||||
}
|
||||
if skipHeader && !out.Skip(int(headerLen)) {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
|
@ -0,0 +1,285 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cryptobyte
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type readASN1Test struct {
|
||||
name string
|
||||
in []byte
|
||||
tag Tag
|
||||
ok bool
|
||||
out interface{}
|
||||
}
|
||||
|
||||
var readASN1TestData = []readASN1Test{
|
||||
{"valid", []byte{0x30, 2, 1, 2}, 0x30, true, []byte{1, 2}},
|
||||
{"truncated", []byte{0x30, 3, 1, 2}, 0x30, false, nil},
|
||||
{"zero length of length", []byte{0x30, 0x80}, 0x30, false, nil},
|
||||
{"invalid long form length", []byte{0x30, 0x81, 1, 1}, 0x30, false, nil},
|
||||
{"non-minimal length", append([]byte{0x30, 0x82, 0, 0x80}, make([]byte, 0x80)...), 0x30, false, nil},
|
||||
{"invalid tag", []byte{0xa1, 3, 0x4, 1, 1}, 31, false, nil},
|
||||
{"high tag", []byte{0x1f, 0x81, 0x80, 0x01, 2, 1, 2}, 0xff /* actually 0x4001, but tag is uint8 */, false, nil},
|
||||
}
|
||||
|
||||
func TestReadASN1(t *testing.T) {
|
||||
for _, test := range readASN1TestData {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var in, out String = test.in, nil
|
||||
ok := in.ReadASN1(&out, test.tag)
|
||||
if ok != test.ok || ok && !bytes.Equal(out, test.out.([]byte)) {
|
||||
t.Errorf("in.ReadASN1() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1Optional(t *testing.T) {
|
||||
var empty String
|
||||
var present bool
|
||||
ok := empty.ReadOptionalASN1(nil, &present, 0xa0)
|
||||
if !ok || present {
|
||||
t.Errorf("empty.ReadOptionalASN1() = %v, want true; present = %v want false", ok, present)
|
||||
}
|
||||
|
||||
var in, out String = []byte{0xa1, 3, 0x4, 1, 1}, nil
|
||||
ok = in.ReadOptionalASN1(&out, &present, 0xa0)
|
||||
if !ok || present {
|
||||
t.Errorf("in.ReadOptionalASN1() = %v, want true, present = %v, want false", ok, present)
|
||||
}
|
||||
ok = in.ReadOptionalASN1(&out, &present, 0xa1)
|
||||
wantBytes := []byte{4, 1, 1}
|
||||
if !ok || !present || !bytes.Equal(out, wantBytes) {
|
||||
t.Errorf("in.ReadOptionalASN1() = %v, want true; present = %v, want true; out = %v, want = %v", ok, present, out, wantBytes)
|
||||
}
|
||||
}
|
||||
|
||||
var optionalOctetStringTestData = []struct {
|
||||
readASN1Test
|
||||
present bool
|
||||
}{
|
||||
{readASN1Test{"empty", []byte{}, 0xa0, true, []byte{}}, false},
|
||||
{readASN1Test{"invalid", []byte{0xa1, 3, 0x4, 2, 1}, 0xa1, false, []byte{}}, true},
|
||||
{readASN1Test{"missing", []byte{0xa1, 3, 0x4, 1, 1}, 0xa0, true, []byte{}}, false},
|
||||
{readASN1Test{"present", []byte{0xa1, 3, 0x4, 1, 1}, 0xa1, true, []byte{1}}, true},
|
||||
}
|
||||
|
||||
func TestReadASN1OptionalOctetString(t *testing.T) {
|
||||
for _, test := range optionalOctetStringTestData {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
in := String(test.in)
|
||||
var out []byte
|
||||
var present bool
|
||||
ok := in.ReadOptionalASN1OctetString(&out, &present, test.tag)
|
||||
if ok != test.ok || present != test.present || !bytes.Equal(out, test.out.([]byte)) {
|
||||
t.Errorf("in.ReadOptionalASN1OctetString() = %v, want %v; present = %v want %v; out = %v, want %v", ok, test.ok, present, test.present, out, test.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const defaultInt = -1
|
||||
|
||||
var optionalIntTestData = []readASN1Test{
|
||||
{"empty", []byte{}, 0xa0, true, defaultInt},
|
||||
{"invalid", []byte{0xa1, 3, 0x2, 2, 127}, 0xa1, false, 0},
|
||||
{"missing", []byte{0xa1, 3, 0x2, 1, 127}, 0xa0, true, defaultInt},
|
||||
{"present", []byte{0xa1, 3, 0x2, 1, 42}, 0xa1, true, 42},
|
||||
}
|
||||
|
||||
func TestReadASN1OptionalInteger(t *testing.T) {
|
||||
for _, test := range optionalIntTestData {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
in := String(test.in)
|
||||
var out int
|
||||
ok := in.ReadOptionalASN1Integer(&out, test.tag, defaultInt)
|
||||
if ok != test.ok || ok && out != test.out.(int) {
|
||||
t.Errorf("in.ReadOptionalASN1Integer() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1IntegerSigned(t *testing.T) {
|
||||
testData64 := []struct {
|
||||
in []byte
|
||||
out int64
|
||||
}{
|
||||
{[]byte{2, 3, 128, 0, 0}, -0x800000},
|
||||
{[]byte{2, 2, 255, 0}, -256},
|
||||
{[]byte{2, 2, 255, 127}, -129},
|
||||
{[]byte{2, 1, 128}, -128},
|
||||
{[]byte{2, 1, 255}, -1},
|
||||
{[]byte{2, 1, 0}, 0},
|
||||
{[]byte{2, 1, 1}, 1},
|
||||
{[]byte{2, 1, 2}, 2},
|
||||
{[]byte{2, 1, 127}, 127},
|
||||
{[]byte{2, 2, 0, 128}, 128},
|
||||
{[]byte{2, 2, 1, 0}, 256},
|
||||
{[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
|
||||
}
|
||||
for i, test := range testData64 {
|
||||
in := String(test.in)
|
||||
var out int64
|
||||
ok := in.ReadASN1Integer(&out)
|
||||
if !ok || out != test.out {
|
||||
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
|
||||
}
|
||||
}
|
||||
|
||||
// Repeat the same cases, reading into a big.Int.
|
||||
t.Run("big.Int", func(t *testing.T) {
|
||||
for i, test := range testData64 {
|
||||
in := String(test.in)
|
||||
var out big.Int
|
||||
ok := in.ReadASN1Integer(&out)
|
||||
if !ok || out.Int64() != test.out {
|
||||
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out.Int64(), test.out)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestReadASN1IntegerUnsigned(t *testing.T) {
|
||||
testData := []struct {
|
||||
in []byte
|
||||
out uint64
|
||||
}{
|
||||
{[]byte{2, 1, 0}, 0},
|
||||
{[]byte{2, 1, 1}, 1},
|
||||
{[]byte{2, 1, 2}, 2},
|
||||
{[]byte{2, 1, 127}, 127},
|
||||
{[]byte{2, 2, 0, 128}, 128},
|
||||
{[]byte{2, 2, 1, 0}, 256},
|
||||
{[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
|
||||
{[]byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}, 0x7fffffffffffffff},
|
||||
{[]byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}, 0x8000000000000000},
|
||||
{[]byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}, 0xffffffffffffffff},
|
||||
}
|
||||
for i, test := range testData {
|
||||
in := String(test.in)
|
||||
var out uint64
|
||||
ok := in.ReadASN1Integer(&out)
|
||||
if !ok || out != test.out {
|
||||
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1IntegerInvalid(t *testing.T) {
|
||||
testData := []String{
|
||||
[]byte{3, 1, 0}, // invalid tag
|
||||
// truncated
|
||||
[]byte{2, 1},
|
||||
[]byte{2, 2, 0},
|
||||
// not minimally encoded
|
||||
[]byte{2, 2, 0, 1},
|
||||
[]byte{2, 2, 0xff, 0xff},
|
||||
}
|
||||
|
||||
for i, test := range testData {
|
||||
var out int64
|
||||
if test.ReadASN1Integer(&out) {
|
||||
t.Errorf("#%d: in.ReadASN1Integer() = true, want false (out = %d)", i, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1ObjectIdentifier(t *testing.T) {
|
||||
testData := []struct {
|
||||
in []byte
|
||||
ok bool
|
||||
out []int
|
||||
}{
|
||||
{[]byte{}, false, []int{}},
|
||||
{[]byte{6, 0}, false, []int{}},
|
||||
{[]byte{5, 1, 85}, false, []int{2, 5}},
|
||||
{[]byte{6, 1, 85}, true, []int{2, 5}},
|
||||
{[]byte{6, 2, 85, 0x02}, true, []int{2, 5, 2}},
|
||||
{[]byte{6, 4, 85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
|
||||
{[]byte{6, 3, 0x81, 0x34, 0x03}, true, []int{2, 100, 3}},
|
||||
{[]byte{6, 7, 85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
|
||||
}
|
||||
|
||||
for i, test := range testData {
|
||||
in := String(test.in)
|
||||
var out asn1.ObjectIdentifier
|
||||
ok := in.ReadASN1ObjectIdentifier(&out)
|
||||
if ok != test.ok || ok && !out.Equal(test.out) {
|
||||
t.Errorf("#%d: in.ReadASN1ObjectIdentifier() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1GeneralizedTime(t *testing.T) {
|
||||
testData := []struct {
|
||||
in string
|
||||
ok bool
|
||||
out time.Time
|
||||
}{
|
||||
{"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)},
|
||||
{"20100102030405", false, time.Time{}},
|
||||
{"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
|
||||
{"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
|
||||
/* These are invalid times. However, the time package normalises times
|
||||
* and they were accepted in some versions. See #11134. */
|
||||
{"00000100000000Z", false, time.Time{}},
|
||||
{"20101302030405Z", false, time.Time{}},
|
||||
{"20100002030405Z", false, time.Time{}},
|
||||
{"20100100030405Z", false, time.Time{}},
|
||||
{"20100132030405Z", false, time.Time{}},
|
||||
{"20100231030405Z", false, time.Time{}},
|
||||
{"20100102240405Z", false, time.Time{}},
|
||||
{"20100102036005Z", false, time.Time{}},
|
||||
{"20100102030460Z", false, time.Time{}},
|
||||
{"-20100102030410Z", false, time.Time{}},
|
||||
{"2010-0102030410Z", false, time.Time{}},
|
||||
{"2010-0002030410Z", false, time.Time{}},
|
||||
{"201001-02030410Z", false, time.Time{}},
|
||||
{"20100102-030410Z", false, time.Time{}},
|
||||
{"2010010203-0410Z", false, time.Time{}},
|
||||
{"201001020304-10Z", false, time.Time{}},
|
||||
}
|
||||
for i, test := range testData {
|
||||
in := String(append([]byte{asn1.TagGeneralizedTime, byte(len(test.in))}, test.in...))
|
||||
var out time.Time
|
||||
ok := in.ReadASN1GeneralizedTime(&out)
|
||||
if ok != test.ok || ok && !reflect.DeepEqual(out, test.out) {
|
||||
t.Errorf("#%d: in.ReadASN1GeneralizedTime() = %v, want %v; out = %q, want %q", i, ok, test.ok, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1BitString(t *testing.T) {
|
||||
testData := []struct {
|
||||
in []byte
|
||||
ok bool
|
||||
out asn1.BitString
|
||||
}{
|
||||
{[]byte{}, false, asn1.BitString{}},
|
||||
{[]byte{0x00}, true, asn1.BitString{}},
|
||||
{[]byte{0x07, 0x00}, true, asn1.BitString{Bytes: []byte{0}, BitLength: 1}},
|
||||
{[]byte{0x07, 0x01}, false, asn1.BitString{}},
|
||||
{[]byte{0x07, 0x40}, false, asn1.BitString{}},
|
||||
{[]byte{0x08, 0x00}, false, asn1.BitString{}},
|
||||
{[]byte{0xff}, false, asn1.BitString{}},
|
||||
{[]byte{0xfe, 0x00}, false, asn1.BitString{}},
|
||||
}
|
||||
for i, test := range testData {
|
||||
in := String(append([]byte{3, byte(len(test.in))}, test.in...))
|
||||
var out asn1.BitString
|
||||
ok := in.ReadASN1BitString(&out)
|
||||
if ok != test.ok || ok && (!bytes.Equal(out.Bytes, test.out.Bytes) || out.BitLength != test.out.BitLength) {
|
||||
t.Errorf("#%d: in.ReadASN1BitString() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cryptobyte
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A Builder builds byte strings from fixed-length and length-prefixed values.
|
||||
// The zero value is a usable Builder that allocates space as needed.
|
||||
type Builder struct {
|
||||
err error
|
||||
result []byte
|
||||
fixedSize bool
|
||||
child *Builder
|
||||
offset int
|
||||
pendingLenLen int
|
||||
pendingIsASN1 bool
|
||||
}
|
||||
|
||||
// NewBuilder creates a Builder that appends its output to the given buffer.
|
||||
// Like append(), the slice will be reallocated if its capacity is exceeded.
|
||||
// Use Bytes to get the final buffer.
|
||||
func NewBuilder(buffer []byte) *Builder {
|
||||
return &Builder{
|
||||
result: buffer,
|
||||
}
|
||||
}
|
||||
|
||||
// NewFixedBuilder creates a Builder that appends its output into the given
|
||||
// buffer. This builder does not reallocate the output buffer. Writes that
|
||||
// would exceed the buffer's capacity are treated as an error.
|
||||
func NewFixedBuilder(buffer []byte) *Builder {
|
||||
return &Builder{
|
||||
result: buffer,
|
||||
fixedSize: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Bytes returns the bytes written by the builder or an error if one has
|
||||
// occurred during during building.
|
||||
func (b *Builder) Bytes() ([]byte, error) {
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
return b.result[b.offset:], nil
|
||||
}
|
||||
|
||||
// BytesOrPanic returns the bytes written by the builder or panics if an error
|
||||
// has occurred during building.
|
||||
func (b *Builder) BytesOrPanic() []byte {
|
||||
if b.err != nil {
|
||||
panic(b.err)
|
||||
}
|
||||
return b.result[b.offset:]
|
||||
}
|
||||
|
||||
// AddUint8 appends an 8-bit value to the byte string.
|
||||
func (b *Builder) AddUint8(v uint8) {
|
||||
b.add(byte(v))
|
||||
}
|
||||
|
||||
// AddUint16 appends a big-endian, 16-bit value to the byte string.
|
||||
func (b *Builder) AddUint16(v uint16) {
|
||||
b.add(byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddUint24 appends a big-endian, 24-bit value to the byte string. The highest
|
||||
// byte of the 32-bit input value is silently truncated.
|
||||
func (b *Builder) AddUint24(v uint32) {
|
||||
b.add(byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddUint32 appends a big-endian, 32-bit value to the byte string.
|
||||
func (b *Builder) AddUint32(v uint32) {
|
||||
b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddBytes appends a sequence of bytes to the byte string.
|
||||
func (b *Builder) AddBytes(v []byte) {
|
||||
b.add(v...)
|
||||
}
|
||||
|
||||
// BuilderContinuation is continuation-passing interface for building
|
||||
// length-prefixed byte sequences. Builder methods for length-prefixed
|
||||
// sequences (AddUint8LengthPrefixed etc.) will invoke the BuilderContinuation
|
||||
// supplied to them. The child builder passed to the continuation can be used
|
||||
// to build the content of the length-prefixed sequence. Example:
|
||||
//
|
||||
// parent := cryptobyte.NewBuilder()
|
||||
// parent.AddUint8LengthPrefixed(func (child *Builder) {
|
||||
// child.AddUint8(42)
|
||||
// child.AddUint8LengthPrefixed(func (grandchild *Builder) {
|
||||
// grandchild.AddUint8(5)
|
||||
// })
|
||||
// })
|
||||
//
|
||||
// It is an error to write more bytes to the child than allowed by the reserved
|
||||
// length prefix. After the continuation returns, the child must be considered
|
||||
// invalid, i.e. users must not store any copies or references of the child
|
||||
// that outlive the continuation.
|
||||
type BuilderContinuation func(child *Builder)
|
||||
|
||||
// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(1, false, f)
|
||||
}
|
||||
|
||||
// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(2, false, f)
|
||||
}
|
||||
|
||||
// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(3, false, f)
|
||||
}
|
||||
|
||||
func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
|
||||
// Subsequent writes can be ignored if the builder has encountered an error.
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
offset := len(b.result)
|
||||
b.add(make([]byte, lenLen)...)
|
||||
|
||||
b.child = &Builder{
|
||||
result: b.result,
|
||||
fixedSize: b.fixedSize,
|
||||
offset: offset,
|
||||
pendingLenLen: lenLen,
|
||||
pendingIsASN1: isASN1,
|
||||
}
|
||||
|
||||
f(b.child)
|
||||
b.flushChild()
|
||||
if b.child != nil {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) flushChild() {
|
||||
if b.child == nil {
|
||||
return
|
||||
}
|
||||
b.child.flushChild()
|
||||
child := b.child
|
||||
b.child = nil
|
||||
|
||||
if child.err != nil {
|
||||
b.err = child.err
|
||||
return
|
||||
}
|
||||
|
||||
length := len(child.result) - child.pendingLenLen - child.offset
|
||||
|
||||
if length < 0 {
|
||||
panic("cryptobyte: internal error") // result unexpectedly shrunk
|
||||
}
|
||||
|
||||
if child.pendingIsASN1 {
|
||||
// For ASN.1, we reserved a single byte for the length. If that turned out
|
||||
// to be incorrect, we have to move the contents along in order to make
|
||||
// space.
|
||||
if child.pendingLenLen != 1 {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
var lenLen, lenByte uint8
|
||||
if int64(length) > 0xfffffffe {
|
||||
b.err = errors.New("pending ASN.1 child too long")
|
||||
return
|
||||
} else if length > 0xffffff {
|
||||
lenLen = 5
|
||||
lenByte = 0x80 | 4
|
||||
} else if length > 0xffff {
|
||||
lenLen = 4
|
||||
lenByte = 0x80 | 3
|
||||
} else if length > 0xff {
|
||||
lenLen = 3
|
||||
lenByte = 0x80 | 2
|
||||
} else if length > 0x7f {
|
||||
lenLen = 2
|
||||
lenByte = 0x80 | 1
|
||||
} else {
|
||||
lenLen = 1
|
||||
lenByte = uint8(length)
|
||||
length = 0
|
||||
}
|
||||
|
||||
// Insert the initial length byte, make space for successive length bytes,
|
||||
// and adjust the offset.
|
||||
child.result[child.offset] = lenByte
|
||||
extraBytes := int(lenLen - 1)
|
||||
if extraBytes != 0 {
|
||||
child.add(make([]byte, extraBytes)...)
|
||||
childStart := child.offset + child.pendingLenLen
|
||||
copy(child.result[childStart+extraBytes:], child.result[childStart:])
|
||||
}
|
||||
child.offset++
|
||||
child.pendingLenLen = extraBytes
|
||||
}
|
||||
|
||||
l := length
|
||||
for i := child.pendingLenLen - 1; i >= 0; i-- {
|
||||
child.result[child.offset+i] = uint8(l)
|
||||
l >>= 8
|
||||
}
|
||||
if l != 0 {
|
||||
b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
|
||||
return
|
||||
}
|
||||
|
||||
if !b.fixedSize {
|
||||
b.result = child.result // In case child reallocated result.
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) add(bytes ...byte) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
if b.child != nil {
|
||||
panic("attempted write while child is pending")
|
||||
}
|
||||
if len(b.result)+len(bytes) < len(bytes) {
|
||||
b.err = errors.New("cryptobyte: length overflow")
|
||||
}
|
||||
if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
|
||||
b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
|
||||
return
|
||||
}
|
||||
b.result = append(b.result, bytes...)
|
||||
}
|
||||
|
||||
// A MarshalingValue marshals itself into a Builder.
|
||||
type MarshalingValue interface {
|
||||
// Marshal is called by Builder.AddValue. It receives a pointer to a builder
|
||||
// to marshal itself into. It may return an error that occurred during
|
||||
// marshaling, such as unset or invalid values.
|
||||
Marshal(b *Builder) error
|
||||
}
|
||||
|
||||
// AddValue calls Marshal on v, passing a pointer to the builder to append to.
|
||||
// If Marshal returns an error, it is set on the Builder so that subsequent
|
||||
// appends don't have an effect.
|
||||
func (b *Builder) AddValue(v MarshalingValue) {
|
||||
err := v.Marshal(b)
|
||||
if err != nil {
|
||||
b.err = err
|
||||
}
|
||||
}
|
|
@ -0,0 +1,379 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cryptobyte
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func builderBytesEq(b *Builder, want ...byte) error {
|
||||
got := b.BytesOrPanic()
|
||||
if !bytes.Equal(got, want) {
|
||||
return fmt.Errorf("Bytes() = %v, want %v", got, want)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
var b Builder
|
||||
v := []byte("foobarbaz")
|
||||
b.AddBytes(v[0:3])
|
||||
b.AddBytes(v[3:4])
|
||||
b.AddBytes(v[4:9])
|
||||
if err := builderBytesEq(&b, v...); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
s := String(b.BytesOrPanic())
|
||||
for _, w := range []string{"foo", "bar", "baz"} {
|
||||
var got []byte
|
||||
if !s.ReadBytes(&got, 3) {
|
||||
t.Errorf("ReadBytes() = false, want true (w = %v)", w)
|
||||
}
|
||||
want := []byte(w)
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Errorf("ReadBytes(): got = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint8(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8(42)
|
||||
if err := builderBytesEq(&b, 42); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s String = b.BytesOrPanic()
|
||||
var v uint8
|
||||
if !s.ReadUint8(&v) {
|
||||
t.Error("ReadUint8() = false, want true")
|
||||
}
|
||||
if v != 42 {
|
||||
t.Errorf("v = %d, want 42", v)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint16(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint16(65534)
|
||||
if err := builderBytesEq(&b, 255, 254); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
var s String = b.BytesOrPanic()
|
||||
var v uint16
|
||||
if !s.ReadUint16(&v) {
|
||||
t.Error("ReadUint16() == false, want true")
|
||||
}
|
||||
if v != 65534 {
|
||||
t.Errorf("v = %d, want 65534", v)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint24(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint24(0xfffefd)
|
||||
if err := builderBytesEq(&b, 255, 254, 253); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s String = b.BytesOrPanic()
|
||||
var v uint32
|
||||
if !s.ReadUint24(&v) {
|
||||
t.Error("ReadUint8() = false, want true")
|
||||
}
|
||||
if v != 0xfffefd {
|
||||
t.Errorf("v = %d, want fffefd", v)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint24Truncation(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint24(0x10111213)
|
||||
if err := builderBytesEq(&b, 0x11, 0x12, 0x13); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint32(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint32(0xfffefdfc)
|
||||
if err := builderBytesEq(&b, 255, 254, 253, 252); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s String = b.BytesOrPanic()
|
||||
var v uint32
|
||||
if !s.ReadUint32(&v) {
|
||||
t.Error("ReadUint8() = false, want true")
|
||||
}
|
||||
if v != 0xfffefdfc {
|
||||
t.Errorf("v = %x, want fffefdfc", v)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUMultiple(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8(23)
|
||||
b.AddUint32(0xfffefdfc)
|
||||
b.AddUint16(42)
|
||||
if err := builderBytesEq(&b, 23, 255, 254, 253, 252, 0, 42); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s String = b.BytesOrPanic()
|
||||
var (
|
||||
x uint8
|
||||
y uint32
|
||||
z uint16
|
||||
)
|
||||
if !s.ReadUint8(&x) || !s.ReadUint32(&y) || !s.ReadUint16(&z) {
|
||||
t.Error("ReadUint8() = false, want true")
|
||||
}
|
||||
if x != 23 || y != 0xfffefdfc || z != 42 {
|
||||
t.Errorf("x, y, z = %d, %d, %d; want 23, 4294901244, 5", x, y, z)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint8LengthPrefixedSimple(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(23)
|
||||
c.AddUint8(42)
|
||||
})
|
||||
if err := builderBytesEq(&b, 2, 23, 42); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var base, child String = b.BytesOrPanic(), nil
|
||||
var x, y uint8
|
||||
if !base.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) ||
|
||||
!child.ReadUint8(&y) {
|
||||
t.Error("parsing failed")
|
||||
}
|
||||
if x != 23 || y != 42 {
|
||||
t.Errorf("want x, y == 23, 42; got %d, %d", x, y)
|
||||
}
|
||||
if len(base) != 0 {
|
||||
t.Errorf("len(base) = %d, want 0", len(base))
|
||||
}
|
||||
if len(child) != 0 {
|
||||
t.Errorf("len(child) = %d, want 0", len(child))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint8LengthPrefixedMulti(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(23)
|
||||
c.AddUint8(42)
|
||||
})
|
||||
b.AddUint8(5)
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(123)
|
||||
c.AddUint8(234)
|
||||
})
|
||||
if err := builderBytesEq(&b, 2, 23, 42, 5, 2, 123, 234); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s, child String = b.BytesOrPanic(), nil
|
||||
var u, v, w, x, y uint8
|
||||
if !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&u) || !child.ReadUint8(&v) ||
|
||||
!s.ReadUint8(&w) || !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || !child.ReadUint8(&y) {
|
||||
t.Error("parsing failed")
|
||||
}
|
||||
if u != 23 || v != 42 || w != 5 || x != 123 || y != 234 {
|
||||
t.Errorf("u, v, w, x, y = %d, %d, %d, %d, %d; want 23, 42, 5, 123, 234",
|
||||
u, v, w, x, y)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
if len(child) != 0 {
|
||||
t.Errorf("len(child) = %d, want 0", len(child))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint8LengthPrefixedNested(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(5)
|
||||
c.AddUint8LengthPrefixed(func(d *Builder) {
|
||||
d.AddUint8(23)
|
||||
d.AddUint8(42)
|
||||
})
|
||||
c.AddUint8(123)
|
||||
})
|
||||
if err := builderBytesEq(&b, 5, 5, 2, 23, 42, 123); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var base, child1, child2 String = b.BytesOrPanic(), nil, nil
|
||||
var u, v, w, x uint8
|
||||
if !base.ReadUint8LengthPrefixed(&child1) {
|
||||
t.Error("parsing base failed")
|
||||
}
|
||||
if !child1.ReadUint8(&u) || !child1.ReadUint8LengthPrefixed(&child2) || !child1.ReadUint8(&x) {
|
||||
t.Error("parsing child1 failed")
|
||||
}
|
||||
if !child2.ReadUint8(&v) || !child2.ReadUint8(&w) {
|
||||
t.Error("parsing child2 failed")
|
||||
}
|
||||
if u != 5 || v != 23 || w != 42 || x != 123 {
|
||||
t.Errorf("u, v, w, x = %d, %d, %d, %d, want 5, 23, 42, 123",
|
||||
u, v, w, x)
|
||||
}
|
||||
if len(base) != 0 {
|
||||
t.Errorf("len(base) = %d, want 0", len(base))
|
||||
}
|
||||
if len(child1) != 0 {
|
||||
t.Errorf("len(child1) = %d, want 0", len(child1))
|
||||
}
|
||||
if len(base) != 0 {
|
||||
t.Errorf("len(child2) = %d, want 0", len(child2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreallocatedBuffer(t *testing.T) {
|
||||
var buf [5]byte
|
||||
b := NewBuilder(buf[0:0])
|
||||
b.AddUint8(1)
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(3)
|
||||
c.AddUint8(4)
|
||||
})
|
||||
b.AddUint16(1286) // Outgrow buf by one byte.
|
||||
want := []byte{1, 2, 3, 4, 0}
|
||||
if !bytes.Equal(buf[:], want) {
|
||||
t.Errorf("buf = %v want %v", buf, want)
|
||||
}
|
||||
if err := builderBytesEq(b, 1, 2, 3, 4, 5, 6); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteWithPendingChild(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8LengthPrefixed(func(d *Builder) {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; c.AddUint8() did not panic")
|
||||
}
|
||||
}()
|
||||
c.AddUint8(2) // panics
|
||||
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
|
||||
}
|
||||
}()
|
||||
b.AddUint8(2) // panics
|
||||
})
|
||||
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
|
||||
}
|
||||
}()
|
||||
b.AddUint8(2) // panics
|
||||
})
|
||||
}
|
||||
|
||||
// ASN.1
|
||||
|
||||
func TestASN1Int64(t *testing.T) {
|
||||
tests := []struct {
|
||||
in int64
|
||||
want []byte
|
||||
}{
|
||||
{-0x800000, []byte{2, 3, 128, 0, 0}},
|
||||
{-256, []byte{2, 2, 255, 0}},
|
||||
{-129, []byte{2, 2, 255, 127}},
|
||||
{-128, []byte{2, 1, 128}},
|
||||
{-1, []byte{2, 1, 255}},
|
||||
{0, []byte{2, 1, 0}},
|
||||
{1, []byte{2, 1, 1}},
|
||||
{2, []byte{2, 1, 2}},
|
||||
{127, []byte{2, 1, 127}},
|
||||
{128, []byte{2, 2, 0, 128}},
|
||||
{256, []byte{2, 2, 1, 0}},
|
||||
{0x800000, []byte{2, 4, 0, 128, 0, 0}},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
var b Builder
|
||||
b.AddASN1Int64(tt.in)
|
||||
if err := builderBytesEq(&b, tt.want...); err != nil {
|
||||
t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
|
||||
}
|
||||
|
||||
var n int64
|
||||
s := String(b.BytesOrPanic())
|
||||
ok := s.ReadASN1Integer(&n)
|
||||
if !ok || n != tt.in {
|
||||
t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
|
||||
ok, n, tt.in, i)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestASN1Uint64(t *testing.T) {
|
||||
tests := []struct {
|
||||
in uint64
|
||||
want []byte
|
||||
}{
|
||||
{0, []byte{2, 1, 0}},
|
||||
{1, []byte{2, 1, 1}},
|
||||
{2, []byte{2, 1, 2}},
|
||||
{127, []byte{2, 1, 127}},
|
||||
{128, []byte{2, 2, 0, 128}},
|
||||
{256, []byte{2, 2, 1, 0}},
|
||||
{0x800000, []byte{2, 4, 0, 128, 0, 0}},
|
||||
{0x7fffffffffffffff, []byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}},
|
||||
{0x8000000000000000, []byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{0xffffffffffffffff, []byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
var b Builder
|
||||
b.AddASN1Uint64(tt.in)
|
||||
if err := builderBytesEq(&b, tt.want...); err != nil {
|
||||
t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
|
||||
}
|
||||
|
||||
var n uint64
|
||||
s := String(b.BytesOrPanic())
|
||||
ok := s.ReadASN1Integer(&n)
|
||||
if !ok || n != tt.in {
|
||||
t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
|
||||
ok, n, tt.in, i)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cryptobyte_test
|
||||
|
||||
import (
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
)
|
||||
|
||||
func ExampleString_lengthPrefixed() {
|
||||
// This is an example of parsing length-prefixed data (as found in, for
|
||||
// example, TLS). Imagine a 16-bit prefixed series of 8-bit prefixed
|
||||
// strings.
|
||||
|
||||
input := cryptobyte.String([]byte{0, 12, 5, 'h', 'e', 'l', 'l', 'o', 5, 'w', 'o', 'r', 'l', 'd'})
|
||||
var result []string
|
||||
|
||||
var values cryptobyte.String
|
||||
if !input.ReadUint16LengthPrefixed(&values) ||
|
||||
!input.Empty() {
|
||||
panic("bad format")
|
||||
}
|
||||
|
||||
for !values.Empty() {
|
||||
var value cryptobyte.String
|
||||
if !values.ReadUint8LengthPrefixed(&value) {
|
||||
panic("bad format")
|
||||
}
|
||||
|
||||
result = append(result, string(value))
|
||||
}
|
||||
|
||||
// Output: []string{"hello", "world"}
|
||||
fmt.Printf("%#v\n", result)
|
||||
}
|
||||
|
||||
func ExampleString_asn1() {
|
||||
// This is an example of parsing ASN.1 data that looks like:
|
||||
// Foo ::= SEQUENCE {
|
||||
// version [6] INTEGER DEFAULT 0
|
||||
// data OCTET STRING
|
||||
// }
|
||||
|
||||
input := cryptobyte.String([]byte{0x30, 12, 0xa6, 3, 2, 1, 2, 4, 5, 'h', 'e', 'l', 'l', 'o'})
|
||||
|
||||
var (
|
||||
version int64
|
||||
data, inner, versionBytes cryptobyte.String
|
||||
haveVersion bool
|
||||
)
|
||||
if !input.ReadASN1(&inner, cryptobyte.Tag(asn1.TagSequence).Constructed()) ||
|
||||
!input.Empty() ||
|
||||
!inner.ReadOptionalASN1(&versionBytes, &haveVersion, cryptobyte.Tag(6).Constructed().ContextSpecific()) ||
|
||||
(haveVersion && !versionBytes.ReadASN1Integer(&version)) ||
|
||||
(haveVersion && !versionBytes.Empty()) ||
|
||||
!inner.ReadASN1(&data, asn1.TagOctetString) ||
|
||||
!inner.Empty() {
|
||||
panic("bad format")
|
||||
}
|
||||
|
||||
// Output: haveVersion: true, version: 2, data: hello
|
||||
fmt.Printf("haveVersion: %t, version: %d, data: %s\n", haveVersion, version, string(data))
|
||||
}
|
||||
|
||||
func ExampleBuilder_asn1() {
|
||||
// This is an example of building ASN.1 data that looks like:
|
||||
// Foo ::= SEQUENCE {
|
||||
// version [6] INTEGER DEFAULT 0
|
||||
// data OCTET STRING
|
||||
// }
|
||||
|
||||
version := int64(2)
|
||||
data := []byte("hello")
|
||||
const defaultVersion = 0
|
||||
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1(cryptobyte.Tag(asn1.TagSequence).Constructed(), func(b *cryptobyte.Builder) {
|
||||
if version != defaultVersion {
|
||||
b.AddASN1(cryptobyte.Tag(6).Constructed().ContextSpecific(), func(b *cryptobyte.Builder) {
|
||||
b.AddASN1Int64(version)
|
||||
})
|
||||
}
|
||||
b.AddASN1OctetString(data)
|
||||
})
|
||||
|
||||
result, err := b.Bytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output: 300ca603020102040568656c6c6f
|
||||
fmt.Printf("%x\n", result)
|
||||
}
|
||||
|
||||
func ExampleBuilder_lengthPrefixed() {
|
||||
// This is an example of building length-prefixed data (as found in,
|
||||
// for example, TLS). Imagine a 16-bit prefixed series of 8-bit
|
||||
// prefixed strings.
|
||||
input := []string{"hello", "world"}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, value := range input {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(value))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
result, err := b.Bytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output: 000c0568656c6c6f05776f726c64
|
||||
fmt.Printf("%x\n", result)
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package cryptobyte implements building and parsing of byte strings for
|
||||
// DER-encoded ASN.1 and TLS messages. See the examples for the Builder and
|
||||
// String types to get started.
|
||||
package cryptobyte // import "golang.org/x/crypto/cryptobyte"
|
||||
|
||||
// String represents a string of bytes. It provides methods for parsing
|
||||
// fixed-length and length-prefixed values from it.
|
||||
type String []byte
|
||||
|
||||
// read advances a String by n bytes and returns them. If less than n bytes
|
||||
// remain, it returns nil.
|
||||
func (s *String) read(n int) []byte {
|
||||
if len(*s) < n {
|
||||
return nil
|
||||
}
|
||||
v := (*s)[:n]
|
||||
*s = (*s)[n:]
|
||||
return v
|
||||
}
|
||||
|
||||
// Skip advances the String by n byte and reports whether it was successful.
|
||||
func (s *String) Skip(n int) bool {
|
||||
return s.read(n) != nil
|
||||
}
|
||||
|
||||
// ReadUint8 decodes an 8-bit value into out and advances over it. It
|
||||
// returns true on success and false on error.
|
||||
func (s *String) ReadUint8(out *uint8) bool {
|
||||
v := s.read(1)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint8(v[0])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
func (s *String) ReadUint16(out *uint16) bool {
|
||||
v := s.read(2)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint16(v[0])<<8 | uint16(v[1])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
func (s *String) ReadUint24(out *uint32) bool {
|
||||
v := s.read(3)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
func (s *String) ReadUint32(out *uint32) bool {
|
||||
v := s.read(4)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readUnsigned(out *uint32, length int) bool {
|
||||
v := s.read(length)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
var result uint32
|
||||
for i := 0; i < length; i++ {
|
||||
result <<= 8
|
||||
result |= uint32(v[i])
|
||||
}
|
||||
*out = result
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
|
||||
lenBytes := s.read(lenLen)
|
||||
if lenBytes == nil {
|
||||
return false
|
||||
}
|
||||
var length uint32
|
||||
for _, b := range lenBytes {
|
||||
length = length << 8
|
||||
length = length | uint32(b)
|
||||
}
|
||||
if int(length) < 0 {
|
||||
// This currently cannot overflow because we read uint24 at most, but check
|
||||
// anyway in case that changes in the future.
|
||||
return false
|
||||
}
|
||||
v := s.read(int(length))
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*outChild = v
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value
|
||||
// into out and advances over it. It returns true on success and false on
|
||||
// error.
|
||||
func (s *String) ReadUint8LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(1, out)
|
||||
}
|
||||
|
||||
// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
|
||||
// length-prefixed value into out and advances over it. It returns true on
|
||||
// success and false on error.
|
||||
func (s *String) ReadUint16LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(2, out)
|
||||
}
|
||||
|
||||
// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
|
||||
// length-prefixed value into out and advances over it. It returns true on
|
||||
// success and false on error.
|
||||
func (s *String) ReadUint24LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(3, out)
|
||||
}
|
||||
|
||||
// ReadBytes reads n bytes into out and advances over them. It returns true on
|
||||
// success and false and error.
|
||||
func (s *String) ReadBytes(out *[]byte, n int) bool {
|
||||
v := s.read(n)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = v
|
||||
return true
|
||||
}
|
||||
|
||||
// CopyBytes copies len(out) bytes into out and advances over them. It returns
|
||||
// true on success and false on error.
|
||||
func (s *String) CopyBytes(out []byte) bool {
|
||||
n := len(out)
|
||||
v := s.read(n)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
return copy(out, v) == n
|
||||
}
|
||||
|
||||
// Empty reports whether the string does not contain any bytes.
|
||||
func (s String) Empty() bool {
|
||||
return len(s) == 0
|
||||
}
|
|
@ -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
|
|
@ -3,12 +3,12 @@
|
|||
// 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: http://bench.cr.yp.to/supercop.html
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF
|
||||
GLOBL ·REDMASK51(SB), 8, $8
|
||||
// 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
|
||||
|
|
|
@ -2,87 +2,64 @@
|
|||
// 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: http://bench.cr.yp.to/supercop.html
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
// func cswap(inout *[5]uint64, v uint64)
|
||||
// func cswap(inout *[4][5]uint64, v uint64)
|
||||
TEXT ·cswap(SB),7,$0
|
||||
MOVQ inout+0(FP),DI
|
||||
MOVQ v+8(FP),SI
|
||||
|
||||
CMPQ SI,$1
|
||||
MOVQ 0(DI),SI
|
||||
MOVQ 80(DI),DX
|
||||
MOVQ 8(DI),CX
|
||||
MOVQ 88(DI),R8
|
||||
MOVQ SI,R9
|
||||
CMOVQEQ DX,SI
|
||||
CMOVQEQ R9,DX
|
||||
MOVQ CX,R9
|
||||
CMOVQEQ R8,CX
|
||||
CMOVQEQ R9,R8
|
||||
MOVQ SI,0(DI)
|
||||
MOVQ DX,80(DI)
|
||||
MOVQ CX,8(DI)
|
||||
MOVQ R8,88(DI)
|
||||
MOVQ 16(DI),SI
|
||||
MOVQ 96(DI),DX
|
||||
MOVQ 24(DI),CX
|
||||
MOVQ 104(DI),R8
|
||||
MOVQ SI,R9
|
||||
CMOVQEQ DX,SI
|
||||
CMOVQEQ R9,DX
|
||||
MOVQ CX,R9
|
||||
CMOVQEQ R8,CX
|
||||
CMOVQEQ R9,R8
|
||||
MOVQ SI,16(DI)
|
||||
MOVQ DX,96(DI)
|
||||
MOVQ CX,24(DI)
|
||||
MOVQ R8,104(DI)
|
||||
MOVQ 32(DI),SI
|
||||
MOVQ 112(DI),DX
|
||||
MOVQ 40(DI),CX
|
||||
MOVQ 120(DI),R8
|
||||
MOVQ SI,R9
|
||||
CMOVQEQ DX,SI
|
||||
CMOVQEQ R9,DX
|
||||
MOVQ CX,R9
|
||||
CMOVQEQ R8,CX
|
||||
CMOVQEQ R9,R8
|
||||
MOVQ SI,32(DI)
|
||||
MOVQ DX,112(DI)
|
||||
MOVQ CX,40(DI)
|
||||
MOVQ R8,120(DI)
|
||||
MOVQ 48(DI),SI
|
||||
MOVQ 128(DI),DX
|
||||
MOVQ 56(DI),CX
|
||||
MOVQ 136(DI),R8
|
||||
MOVQ SI,R9
|
||||
CMOVQEQ DX,SI
|
||||
CMOVQEQ R9,DX
|
||||
MOVQ CX,R9
|
||||
CMOVQEQ R8,CX
|
||||
CMOVQEQ R9,R8
|
||||
MOVQ SI,48(DI)
|
||||
MOVQ DX,128(DI)
|
||||
MOVQ CX,56(DI)
|
||||
MOVQ R8,136(DI)
|
||||
MOVQ 64(DI),SI
|
||||
MOVQ 144(DI),DX
|
||||
MOVQ 72(DI),CX
|
||||
MOVQ 152(DI),R8
|
||||
MOVQ SI,R9
|
||||
CMOVQEQ DX,SI
|
||||
CMOVQEQ R9,DX
|
||||
MOVQ CX,R9
|
||||
CMOVQEQ R8,CX
|
||||
CMOVQEQ R9,R8
|
||||
MOVQ SI,64(DI)
|
||||
MOVQ DX,144(DI)
|
||||
MOVQ CX,72(DI)
|
||||
MOVQ R8,152(DI)
|
||||
MOVQ DI,AX
|
||||
MOVQ SI,DX
|
||||
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
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
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.
|
||||
|
||||
|
@ -50,17 +54,11 @@ func feCopy(dst, src *fieldElement) {
|
|||
//
|
||||
// Preconditions: b in {0,1}.
|
||||
func feCSwap(f, g *fieldElement, b int32) {
|
||||
var x fieldElement
|
||||
b = -b
|
||||
for i := range x {
|
||||
x[i] = b & (f[i] ^ g[i])
|
||||
}
|
||||
|
||||
for i := range f {
|
||||
f[i] ^= x[i]
|
||||
}
|
||||
for i := range g {
|
||||
g[i] ^= x[i]
|
||||
t := b & (f[i] ^ g[i])
|
||||
f[i] ^= t
|
||||
g[i] ^= t
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,12 +73,7 @@ func load3(in []byte) int64 {
|
|||
|
||||
// load4 reads a 32-bit, little-endian value from in.
|
||||
func load4(in []byte) int64 {
|
||||
var r int64
|
||||
r = int64(in[0])
|
||||
r |= int64(in[1]) << 8
|
||||
r |= int64(in[2]) << 16
|
||||
r |= int64(in[3]) << 24
|
||||
return r
|
||||
return int64(binary.LittleEndian.Uint32(in))
|
||||
}
|
||||
|
||||
func feFromBytes(dst *fieldElement, src *[32]byte) {
|
||||
|
|
|
@ -27,3 +27,13 @@ func TestBaseScalarMult(t *testing.T) {
|
|||
t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScalarBaseMult(b *testing.B) {
|
||||
var in, out [32]byte
|
||||
in[0] = 1
|
||||
|
||||
b.SetBytes(32)
|
||||
for i := 0; i < b.N; i++ {
|
||||
ScalarBaseMult(&out, &in)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// 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 http://cr.yp.to/ecdh.html
|
||||
// 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.
|
||||
|
|
|
@ -3,33 +3,22 @@
|
|||
// 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: http://bench.cr.yp.to/supercop.html
|
||||
// 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,$96-8
|
||||
TEXT ·freeze(SB),7,$0-8
|
||||
MOVQ inout+0(FP), DI
|
||||
|
||||
MOVQ SP,R11
|
||||
MOVQ $31,CX
|
||||
NOTQ CX
|
||||
ANDQ CX,SP
|
||||
ADDQ $32,SP
|
||||
|
||||
MOVQ R11,0(SP)
|
||||
MOVQ R12,8(SP)
|
||||
MOVQ R13,16(SP)
|
||||
MOVQ R14,24(SP)
|
||||
MOVQ R15,32(SP)
|
||||
MOVQ BX,40(SP)
|
||||
MOVQ BP,48(SP)
|
||||
MOVQ 0(DI),SI
|
||||
MOVQ 8(DI),DX
|
||||
MOVQ 16(DI),CX
|
||||
MOVQ 24(DI),R8
|
||||
MOVQ 32(DI),R9
|
||||
MOVQ ·REDMASK51(SB),AX
|
||||
MOVQ $REDMASK51,AX
|
||||
MOVQ AX,R10
|
||||
SUBQ $18,R10
|
||||
MOVQ $3,R11
|
||||
|
@ -81,14 +70,4 @@ REDUCELOOP:
|
|||
MOVQ CX,16(DI)
|
||||
MOVQ R8,24(DI)
|
||||
MOVQ R9,32(DI)
|
||||
MOVQ 0(SP),R11
|
||||
MOVQ 8(SP),R12
|
||||
MOVQ 16(SP),R13
|
||||
MOVQ 24(SP),R14
|
||||
MOVQ 32(SP),R15
|
||||
MOVQ 40(SP),BX
|
||||
MOVQ 48(SP),BP
|
||||
MOVQ R11,SP
|
||||
MOVQ DI,AX
|
||||
MOVQ SI,DX
|
||||
RET
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,40 +3,28 @@
|
|||
// 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: http://bench.cr.yp.to/supercop.html
|
||||
// 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,$128-24
|
||||
TEXT ·mul(SB),0,$16-24
|
||||
MOVQ dest+0(FP), DI
|
||||
MOVQ a+8(FP), SI
|
||||
MOVQ b+16(FP), DX
|
||||
|
||||
MOVQ SP,R11
|
||||
MOVQ $31,CX
|
||||
NOTQ CX
|
||||
ANDQ CX,SP
|
||||
ADDQ $32,SP
|
||||
|
||||
MOVQ R11,0(SP)
|
||||
MOVQ R12,8(SP)
|
||||
MOVQ R13,16(SP)
|
||||
MOVQ R14,24(SP)
|
||||
MOVQ R15,32(SP)
|
||||
MOVQ BX,40(SP)
|
||||
MOVQ BP,48(SP)
|
||||
MOVQ DI,56(SP)
|
||||
MOVQ DX,CX
|
||||
MOVQ 24(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MOVQ AX,64(SP)
|
||||
MOVQ AX,0(SP)
|
||||
MULQ 16(CX)
|
||||
MOVQ AX,R8
|
||||
MOVQ DX,R9
|
||||
MOVQ 32(SI),DX
|
||||
IMUL3Q $19,DX,AX
|
||||
MOVQ AX,72(SP)
|
||||
MOVQ AX,8(SP)
|
||||
MULQ 8(CX)
|
||||
ADDQ AX,R8
|
||||
ADCQ DX,R9
|
||||
|
@ -111,11 +99,11 @@ TEXT ·mul(SB),0,$128-24
|
|||
MULQ 8(CX)
|
||||
ADDQ AX,BX
|
||||
ADCQ DX,BP
|
||||
MOVQ 64(SP),AX
|
||||
MOVQ 0(SP),AX
|
||||
MULQ 24(CX)
|
||||
ADDQ AX,R10
|
||||
ADCQ DX,R11
|
||||
MOVQ 64(SP),AX
|
||||
MOVQ 0(SP),AX
|
||||
MULQ 32(CX)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
|
@ -123,19 +111,19 @@ TEXT ·mul(SB),0,$128-24
|
|||
MULQ 0(CX)
|
||||
ADDQ AX,BX
|
||||
ADCQ DX,BP
|
||||
MOVQ 72(SP),AX
|
||||
MOVQ 8(SP),AX
|
||||
MULQ 16(CX)
|
||||
ADDQ AX,R10
|
||||
ADCQ DX,R11
|
||||
MOVQ 72(SP),AX
|
||||
MOVQ 8(SP),AX
|
||||
MULQ 24(CX)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ 72(SP),AX
|
||||
MOVQ 8(SP),AX
|
||||
MULQ 32(CX)
|
||||
ADDQ AX,R14
|
||||
ADCQ DX,R15
|
||||
MOVQ ·REDMASK51(SB),SI
|
||||
MOVQ $REDMASK51,SI
|
||||
SHLQ $13,R9:R8
|
||||
ANDQ SI,R8
|
||||
SHLQ $13,R11:R10
|
||||
|
@ -178,14 +166,4 @@ TEXT ·mul(SB),0,$128-24
|
|||
MOVQ R9,16(DI)
|
||||
MOVQ AX,24(DI)
|
||||
MOVQ R10,32(DI)
|
||||
MOVQ 0(SP),R11
|
||||
MOVQ 8(SP),R12
|
||||
MOVQ 16(SP),R13
|
||||
MOVQ 24(SP),R14
|
||||
MOVQ 32(SP),R15
|
||||
MOVQ 40(SP),BX
|
||||
MOVQ 48(SP),BP
|
||||
MOVQ R11,SP
|
||||
MOVQ DI,AX
|
||||
MOVQ SI,DX
|
||||
RET
|
||||
|
|
|
@ -3,28 +3,17 @@
|
|||
// 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: http://bench.cr.yp.to/supercop.html
|
||||
// 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,$96-16
|
||||
TEXT ·square(SB),7,$0-16
|
||||
MOVQ out+0(FP), DI
|
||||
MOVQ in+8(FP), SI
|
||||
|
||||
MOVQ SP,R11
|
||||
MOVQ $31,CX
|
||||
NOTQ CX
|
||||
ANDQ CX,SP
|
||||
ADDQ $32, SP
|
||||
|
||||
MOVQ R11,0(SP)
|
||||
MOVQ R12,8(SP)
|
||||
MOVQ R13,16(SP)
|
||||
MOVQ R14,24(SP)
|
||||
MOVQ R15,32(SP)
|
||||
MOVQ BX,40(SP)
|
||||
MOVQ BP,48(SP)
|
||||
MOVQ 0(SI),AX
|
||||
MULQ 0(SI)
|
||||
MOVQ AX,CX
|
||||
|
@ -97,7 +86,7 @@ TEXT ·square(SB),7,$96-16
|
|||
MULQ 32(SI)
|
||||
ADDQ AX,R13
|
||||
ADCQ DX,R14
|
||||
MOVQ ·REDMASK51(SB),SI
|
||||
MOVQ $REDMASK51,SI
|
||||
SHLQ $13,R8:CX
|
||||
ANDQ SI,CX
|
||||
SHLQ $13,R10:R9
|
||||
|
@ -140,14 +129,4 @@ TEXT ·square(SB),7,$96-16
|
|||
MOVQ R9,16(DI)
|
||||
MOVQ AX,24(DI)
|
||||
MOVQ R10,32(DI)
|
||||
MOVQ 0(SP),R11
|
||||
MOVQ 8(SP),R12
|
||||
MOVQ 16(SP),R13
|
||||
MOVQ 24(SP),R14
|
||||
MOVQ 32(SP),R15
|
||||
MOVQ 40(SP),BX
|
||||
MOVQ 48(SP),BP
|
||||
MOVQ R11,SP
|
||||
MOVQ DI,AX
|
||||
MOVQ SI,DX
|
||||
RET
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package ed25519 implements the Ed25519 signature algorithm. See
|
||||
// http://ed25519.cr.yp.to/.
|
||||
// https://ed25519.cr.yp.to/.
|
||||
//
|
||||
// These functions are also compatible with the “Ed25519” function defined in
|
||||
// https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05.
|
||||
|
@ -13,10 +13,10 @@ package ed25519
|
|||
// from SUPERCOP.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/sha512"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"io"
|
||||
"strconv"
|
||||
|
@ -177,5 +177,5 @@ func Verify(publicKey PublicKey, message, sig []byte) bool {
|
|||
|
||||
var checkR [32]byte
|
||||
R.ToBytes(&checkR)
|
||||
return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1
|
||||
return bytes.Equal(sig[:32], checkR[:])
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ func TestCryptoSigner(t *testing.T) {
|
|||
|
||||
func TestGolden(t *testing.T) {
|
||||
// sign.input.gz is a selection of test cases from
|
||||
// http://ed25519.cr.yp.to/python/sign.input
|
||||
// https://ed25519.cr.yp.to/python/sign.input
|
||||
testDataZ, err := os.Open("testdata/sign.input.gz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package md4_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/md4"
|
||||
)
|
||||
|
||||
func ExampleNew() {
|
||||
h := md4.New()
|
||||
data := "These pretzels are making me thirsty."
|
||||
io.WriteString(h, data)
|
||||
fmt.Printf("%x", h.Sum(nil))
|
||||
// Output: 48c4e365090b30a32f084c4888deceaa
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package box_test
|
||||
|
||||
import (
|
||||
crypto_rand "crypto/rand" // Custom so it's clear which rand we're using.
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
)
|
||||
|
||||
func Example() {
|
||||
senderPublicKey, senderPrivateKey, err := box.GenerateKey(crypto_rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
recipientPublicKey, recipientPrivateKey, err := box.GenerateKey(crypto_rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// You must use a different nonce for each message you encrypt with the
|
||||
// same key. Since the nonce here is 192 bits long, a random value
|
||||
// provides a sufficiently small probability of repeats.
|
||||
var nonce [24]byte
|
||||
if _, err := io.ReadFull(crypto_rand.Reader, nonce[:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
msg := []byte("Alas, poor Yorick! I knew him, Horatio")
|
||||
// This encrypts msg and appends the result to the nonce.
|
||||
encrypted := box.Seal(nonce[:], msg, &nonce, recipientPublicKey, senderPrivateKey)
|
||||
|
||||
// The recipient can decrypt the message using their private key and the
|
||||
// sender's public key. When you decrypt, you must use the same nonce you
|
||||
// used to encrypt the message. One way to achieve this is to store the
|
||||
// nonce alongside the encrypted message. Above, we stored the nonce in the
|
||||
// first 24 bytes of the encrypted text.
|
||||
var decryptNonce [24]byte
|
||||
copy(decryptNonce[:], encrypted[:24])
|
||||
decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey)
|
||||
if !ok {
|
||||
panic("decryption error")
|
||||
}
|
||||
fmt.Println(string(decrypted))
|
||||
// Output: Alas, poor Yorick! I knew him, Horatio
|
||||
}
|
||||
|
||||
func Example_precompute() {
|
||||
senderPublicKey, senderPrivateKey, err := box.GenerateKey(crypto_rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
recipientPublicKey, recipientPrivateKey, err := box.GenerateKey(crypto_rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The shared key can be used to speed up processing when using the same
|
||||
// pair of keys repeatedly.
|
||||
sharedEncryptKey := new([32]byte)
|
||||
box.Precompute(sharedEncryptKey, recipientPublicKey, senderPrivateKey)
|
||||
|
||||
// You must use a different nonce for each message you encrypt with the
|
||||
// same key. Since the nonce here is 192 bits long, a random value
|
||||
// provides a sufficiently small probability of repeats.
|
||||
var nonce [24]byte
|
||||
if _, err := io.ReadFull(crypto_rand.Reader, nonce[:]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
msg := []byte("A fellow of infinite jest, of most excellent fancy")
|
||||
// This encrypts msg and appends the result to the nonce.
|
||||
encrypted := box.SealAfterPrecomputation(nonce[:], msg, &nonce, sharedEncryptKey)
|
||||
|
||||
// The shared key can be used to speed up processing when using the same
|
||||
// pair of keys repeatedly.
|
||||
var sharedDecryptKey [32]byte
|
||||
box.Precompute(&sharedDecryptKey, senderPublicKey, recipientPrivateKey)
|
||||
|
||||
// The recipient can decrypt the message using the shared key. When you
|
||||
// decrypt, you must use the same nonce you used to encrypt the message.
|
||||
// One way to achieve this is to store the nonce alongside the encrypted
|
||||
// message. Above, we stored the nonce in the first 24 bytes of the
|
||||
// encrypted text.
|
||||
var decryptNonce [24]byte
|
||||
copy(decryptNonce[:], encrypted[:24])
|
||||
decrypted, ok := box.OpenAfterPrecomputation(nil, encrypted[24:], &decryptNonce, &sharedDecryptKey)
|
||||
if !ok {
|
||||
panic("decryption error")
|
||||
}
|
||||
fmt.Println(string(decrypted))
|
||||
// Output: A fellow of infinite jest, of most excellent fancy
|
||||
}
|
|
@ -43,7 +43,7 @@ func Example() {
|
|||
// 24 bytes of the encrypted text.
|
||||
var decryptNonce [24]byte
|
||||
copy(decryptNonce[:], encrypted[:24])
|
||||
decrypted, ok := secretbox.Open([]byte{}, encrypted[24:], &decryptNonce, &secretKey)
|
||||
decrypted, ok := secretbox.Open(nil, encrypted[24:], &decryptNonce, &secretKey)
|
||||
if !ok {
|
||||
panic("decryption error")
|
||||
}
|
||||
|
|
|
@ -89,3 +89,66 @@ func TestAppend(t *testing.T) {
|
|||
t.Fatalf("Seal didn't correctly append with sufficient capacity.")
|
||||
}
|
||||
}
|
||||
|
||||
func benchmarkSealSize(b *testing.B, size int) {
|
||||
message := make([]byte, size)
|
||||
out := make([]byte, size+Overhead)
|
||||
var nonce [24]byte
|
||||
var key [32]byte
|
||||
|
||||
b.SetBytes(int64(size))
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
out = Seal(out[:0], message, &nonce, &key)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSeal8Bytes(b *testing.B) {
|
||||
benchmarkSealSize(b, 8)
|
||||
}
|
||||
|
||||
func BenchmarkSeal100Bytes(b *testing.B) {
|
||||
benchmarkSealSize(b, 100)
|
||||
}
|
||||
|
||||
func BenchmarkSeal1K(b *testing.B) {
|
||||
benchmarkSealSize(b, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkSeal8K(b *testing.B) {
|
||||
benchmarkSealSize(b, 8192)
|
||||
}
|
||||
|
||||
func benchmarkOpenSize(b *testing.B, size int) {
|
||||
msg := make([]byte, size)
|
||||
result := make([]byte, size)
|
||||
var nonce [24]byte
|
||||
var key [32]byte
|
||||
box := Seal(nil, msg, &nonce, &key)
|
||||
|
||||
b.SetBytes(int64(size))
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, ok := Open(result[:0], box, &nonce, &key); !ok {
|
||||
panic("Open failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkOpen8Bytes(b *testing.B) {
|
||||
benchmarkOpenSize(b, 8)
|
||||
}
|
||||
|
||||
func BenchmarkOpen100Bytes(b *testing.B) {
|
||||
benchmarkOpenSize(b, 100)
|
||||
}
|
||||
|
||||
func BenchmarkOpen1K(b *testing.B) {
|
||||
benchmarkOpenSize(b, 1024)
|
||||
}
|
||||
|
||||
func BenchmarkOpen8K(b *testing.B) {
|
||||
benchmarkOpenSize(b, 8192)
|
||||
}
|
||||
|
|
|
@ -13,11 +13,14 @@ import (
|
|||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
_ "crypto/sha1"
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"time"
|
||||
|
@ -113,12 +116,11 @@ type basicResponse struct {
|
|||
}
|
||||
|
||||
type responseData struct {
|
||||
Raw asn1.RawContent
|
||||
Version int `asn1:"optional,default:0,explicit,tag:0"`
|
||||
RawResponderName asn1.RawValue `asn1:"optional,explicit,tag:1"`
|
||||
KeyHash []byte `asn1:"optional,explicit,tag:2"`
|
||||
ProducedAt time.Time `asn1:"generalized"`
|
||||
Responses []singleResponse
|
||||
Raw asn1.RawContent
|
||||
Version int `asn1:"optional,default:0,explicit,tag:0"`
|
||||
RawResponderID asn1.RawValue
|
||||
ProducedAt time.Time `asn1:"generalized"`
|
||||
Responses []singleResponse
|
||||
}
|
||||
|
||||
type singleResponse struct {
|
||||
|
@ -355,6 +357,20 @@ type Response struct {
|
|||
Signature []byte
|
||||
SignatureAlgorithm x509.SignatureAlgorithm
|
||||
|
||||
// IssuerHash is the hash used to compute the IssuerNameHash and IssuerKeyHash.
|
||||
// Valid values are crypto.SHA1, crypto.SHA256, crypto.SHA384, and crypto.SHA512.
|
||||
// If zero, the default is crypto.SHA1.
|
||||
IssuerHash crypto.Hash
|
||||
|
||||
// RawResponderName optionally contains the DER-encoded subject of the
|
||||
// responder certificate. Exactly one of RawResponderName and
|
||||
// ResponderKeyHash is set.
|
||||
RawResponderName []byte
|
||||
// ResponderKeyHash optionally contains the SHA-1 hash of the
|
||||
// responder's public key. Exactly one of RawResponderName and
|
||||
// ResponderKeyHash is set.
|
||||
ResponderKeyHash []byte
|
||||
|
||||
// Extensions contains raw X.509 extensions from the singleExtensions field
|
||||
// of the OCSP response. When parsing certificates, this can be used to
|
||||
// extract non-critical extensions that are not parsed by this package. When
|
||||
|
@ -434,8 +450,8 @@ func ParseRequest(bytes []byte) (*Request, error) {
|
|||
// then the signature over the response is checked. If issuer is not nil then
|
||||
// it will be used to validate the signature or embedded certificate.
|
||||
//
|
||||
// Invalid signatures or parse failures will result in a ParseError. Error
|
||||
// responses will result in a ResponseError.
|
||||
// Invalid responses and parse failures will result in a ParseError.
|
||||
// Error responses will result in a ResponseError.
|
||||
func ParseResponse(bytes []byte, issuer *x509.Certificate) (*Response, error) {
|
||||
return ParseResponseForCert(bytes, nil, issuer)
|
||||
}
|
||||
|
@ -446,8 +462,8 @@ func ParseResponse(bytes []byte, issuer *x509.Certificate) (*Response, error) {
|
|||
// issuer is not nil then it will be used to validate the signature or embedded
|
||||
// certificate.
|
||||
//
|
||||
// Invalid signatures or parse failures will result in a ParseError. Error
|
||||
// responses will result in a ResponseError.
|
||||
// Invalid responses and parse failures will result in a ParseError.
|
||||
// Error responses will result in a ResponseError.
|
||||
func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Response, error) {
|
||||
var resp responseASN1
|
||||
rest, err := asn1.Unmarshal(bytes, &resp)
|
||||
|
@ -480,10 +496,51 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
|
|||
return nil, ParseError("OCSP response contains bad number of responses")
|
||||
}
|
||||
|
||||
var singleResp singleResponse
|
||||
if cert == nil {
|
||||
singleResp = basicResp.TBSResponseData.Responses[0]
|
||||
} else {
|
||||
match := false
|
||||
for _, resp := range basicResp.TBSResponseData.Responses {
|
||||
if cert.SerialNumber.Cmp(resp.CertID.SerialNumber) == 0 {
|
||||
singleResp = resp
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
return nil, ParseError("no response matching the supplied certificate")
|
||||
}
|
||||
}
|
||||
|
||||
ret := &Response{
|
||||
TBSResponseData: basicResp.TBSResponseData.Raw,
|
||||
Signature: basicResp.Signature.RightAlign(),
|
||||
SignatureAlgorithm: getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm),
|
||||
Extensions: singleResp.SingleExtensions,
|
||||
SerialNumber: singleResp.CertID.SerialNumber,
|
||||
ProducedAt: basicResp.TBSResponseData.ProducedAt,
|
||||
ThisUpdate: singleResp.ThisUpdate,
|
||||
NextUpdate: singleResp.NextUpdate,
|
||||
}
|
||||
|
||||
// Handle the ResponderID CHOICE tag. ResponderID can be flattened into
|
||||
// TBSResponseData once https://go-review.googlesource.com/34503 has been
|
||||
// released.
|
||||
rawResponderID := basicResp.TBSResponseData.RawResponderID
|
||||
switch rawResponderID.Tag {
|
||||
case 1: // Name
|
||||
var rdn pkix.RDNSequence
|
||||
if rest, err := asn1.Unmarshal(rawResponderID.Bytes, &rdn); err != nil || len(rest) != 0 {
|
||||
return nil, ParseError("invalid responder name")
|
||||
}
|
||||
ret.RawResponderName = rawResponderID.Bytes
|
||||
case 2: // KeyHash
|
||||
if rest, err := asn1.Unmarshal(rawResponderID.Bytes, &ret.ResponderKeyHash); err != nil || len(rest) != 0 {
|
||||
return nil, ParseError("invalid responder key hash")
|
||||
}
|
||||
default:
|
||||
return nil, ParseError("invalid responder id tag")
|
||||
}
|
||||
|
||||
if len(basicResp.Certificates) > 0 {
|
||||
|
@ -493,52 +550,47 @@ func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Respon
|
|||
}
|
||||
|
||||
if err := ret.CheckSignatureFrom(ret.Certificate); err != nil {
|
||||
return nil, ParseError("bad OCSP signature")
|
||||
return nil, ParseError("bad signature on embedded certificate: " + err.Error())
|
||||
}
|
||||
|
||||
if issuer != nil {
|
||||
if err := issuer.CheckSignature(ret.Certificate.SignatureAlgorithm, ret.Certificate.RawTBSCertificate, ret.Certificate.Signature); err != nil {
|
||||
return nil, ParseError("bad signature on embedded certificate")
|
||||
return nil, ParseError("bad OCSP signature: " + err.Error())
|
||||
}
|
||||
}
|
||||
} else if issuer != nil {
|
||||
if err := ret.CheckSignatureFrom(issuer); err != nil {
|
||||
return nil, ParseError("bad OCSP signature")
|
||||
return nil, ParseError("bad OCSP signature: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
var r singleResponse
|
||||
for _, resp := range basicResp.TBSResponseData.Responses {
|
||||
if cert == nil || cert.SerialNumber.Cmp(resp.CertID.SerialNumber) == 0 {
|
||||
r = resp
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for _, ext := range r.SingleExtensions {
|
||||
for _, ext := range singleResp.SingleExtensions {
|
||||
if ext.Critical {
|
||||
return nil, ParseError("unsupported critical extension")
|
||||
}
|
||||
}
|
||||
ret.Extensions = r.SingleExtensions
|
||||
|
||||
ret.SerialNumber = r.CertID.SerialNumber
|
||||
for h, oid := range hashOIDs {
|
||||
if singleResp.CertID.HashAlgorithm.Algorithm.Equal(oid) {
|
||||
ret.IssuerHash = h
|
||||
break
|
||||
}
|
||||
}
|
||||
if ret.IssuerHash == 0 {
|
||||
return nil, ParseError("unsupported issuer hash algorithm")
|
||||
}
|
||||
|
||||
switch {
|
||||
case bool(r.Good):
|
||||
case bool(singleResp.Good):
|
||||
ret.Status = Good
|
||||
case bool(r.Unknown):
|
||||
case bool(singleResp.Unknown):
|
||||
ret.Status = Unknown
|
||||
default:
|
||||
ret.Status = Revoked
|
||||
ret.RevokedAt = r.Revoked.RevocationTime
|
||||
ret.RevocationReason = int(r.Revoked.Reason)
|
||||
ret.RevokedAt = singleResp.Revoked.RevocationTime
|
||||
ret.RevocationReason = int(singleResp.Revoked.Reason)
|
||||
}
|
||||
|
||||
ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
|
||||
ret.ThisUpdate = r.ThisUpdate
|
||||
ret.NextUpdate = r.NextUpdate
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
|
@ -602,15 +654,16 @@ func CreateRequest(cert, issuer *x509.Certificate, opts *RequestOptions) ([]byte
|
|||
// CreateResponse returns a DER-encoded OCSP response with the specified contents.
|
||||
// The fields in the response are populated as follows:
|
||||
//
|
||||
// The responder cert is used to populate the ResponderName field, and the certificate
|
||||
// itself is provided alongside the OCSP response signature.
|
||||
// The responder cert is used to populate the responder's name field, and the
|
||||
// certificate itself is provided alongside the OCSP response signature.
|
||||
//
|
||||
// The issuer cert is used to puplate the IssuerNameHash and IssuerKeyHash fields.
|
||||
// (SHA-1 is used for the hash function; this is not configurable.)
|
||||
//
|
||||
// The template is used to populate the SerialNumber, RevocationStatus, RevokedAt,
|
||||
// RevocationReason, ThisUpdate, and NextUpdate fields.
|
||||
//
|
||||
// If template.IssuerHash is not set, SHA1 will be used.
|
||||
//
|
||||
// The ProducedAt date is automatically set to the current date, to the nearest minute.
|
||||
func CreateResponse(issuer, responderCert *x509.Certificate, template Response, priv crypto.Signer) ([]byte, error) {
|
||||
var publicKeyInfo struct {
|
||||
|
@ -621,7 +674,18 @@ func CreateResponse(issuer, responderCert *x509.Certificate, template Response,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
h := sha1.New()
|
||||
if template.IssuerHash == 0 {
|
||||
template.IssuerHash = crypto.SHA1
|
||||
}
|
||||
hashOID := getOIDFromHashAlgorithm(template.IssuerHash)
|
||||
if hashOID == nil {
|
||||
return nil, errors.New("unsupported issuer hash algorithm")
|
||||
}
|
||||
|
||||
if !template.IssuerHash.Available() {
|
||||
return nil, fmt.Errorf("issuer hash algorithm %v not linked into binary", template.IssuerHash)
|
||||
}
|
||||
h := template.IssuerHash.New()
|
||||
h.Write(publicKeyInfo.PublicKey.RightAlign())
|
||||
issuerKeyHash := h.Sum(nil)
|
||||
|
||||
|
@ -632,7 +696,7 @@ func CreateResponse(issuer, responderCert *x509.Certificate, template Response,
|
|||
innerResponse := singleResponse{
|
||||
CertID: certID{
|
||||
HashAlgorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: hashOIDs[crypto.SHA1],
|
||||
Algorithm: hashOID,
|
||||
Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */},
|
||||
},
|
||||
NameHash: issuerNameHash,
|
||||
|
@ -656,17 +720,17 @@ func CreateResponse(issuer, responderCert *x509.Certificate, template Response,
|
|||
}
|
||||
}
|
||||
|
||||
responderName := asn1.RawValue{
|
||||
rawResponderID := asn1.RawValue{
|
||||
Class: 2, // context-specific
|
||||
Tag: 1, // explicit tag
|
||||
Tag: 1, // Name (explicit tag)
|
||||
IsCompound: true,
|
||||
Bytes: responderCert.RawSubject,
|
||||
}
|
||||
tbsResponseData := responseData{
|
||||
Version: 0,
|
||||
RawResponderName: responderName,
|
||||
ProducedAt: time.Now().Truncate(time.Minute).UTC(),
|
||||
Responses: []singleResponse{innerResponse},
|
||||
Version: 0,
|
||||
RawResponderID: rawResponderID,
|
||||
ProducedAt: time.Now().Truncate(time.Minute).UTC(),
|
||||
Responses: []singleResponse{innerResponse},
|
||||
}
|
||||
|
||||
tbsResponseDataDER, err := asn1.Marshal(tbsResponseData)
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.7
|
||||
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
|
@ -22,7 +24,13 @@ func TestOCSPDecode(t *testing.T) {
|
|||
responseBytes, _ := hex.DecodeString(ocspResponseHex)
|
||||
resp, err := ParseResponse(responseBytes, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
responderCert, _ := hex.DecodeString(startComResponderCertHex)
|
||||
responder, err := x509.ParseCertificate(responderCert)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := Response{
|
||||
|
@ -31,6 +39,7 @@ func TestOCSPDecode(t *testing.T) {
|
|||
RevocationReason: Unspecified,
|
||||
ThisUpdate: time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC),
|
||||
NextUpdate: time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC),
|
||||
RawResponderName: responder.RawSubject,
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resp.ThisUpdate, expected.ThisUpdate) {
|
||||
|
@ -52,6 +61,14 @@ func TestOCSPDecode(t *testing.T) {
|
|||
if resp.RevocationReason != expected.RevocationReason {
|
||||
t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, expected.RevocationReason)
|
||||
}
|
||||
|
||||
if !bytes.Equal(resp.RawResponderName, expected.RawResponderName) {
|
||||
t.Errorf("resp.RawResponderName: got %x, want %x", resp.RawResponderName, expected.RawResponderName)
|
||||
}
|
||||
|
||||
if !bytes.Equal(resp.ResponderKeyHash, expected.ResponderKeyHash) {
|
||||
t.Errorf("resp.ResponderKeyHash: got %x, want %x", resp.ResponderKeyHash, expected.ResponderKeyHash)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOCSPDecodeWithoutCert(t *testing.T) {
|
||||
|
@ -208,7 +225,6 @@ func TestOCSPResponse(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
producedAt := time.Now().Truncate(time.Minute)
|
||||
thisUpdate := time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC)
|
||||
nextUpdate := time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC)
|
||||
template := Response{
|
||||
|
@ -222,46 +238,77 @@ func TestOCSPResponse(t *testing.T) {
|
|||
ExtraExtensions: extensions,
|
||||
}
|
||||
|
||||
responseBytes, err := CreateResponse(issuer, responder, template, responderPrivateKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
template.IssuerHash = crypto.MD5
|
||||
_, err = CreateResponse(issuer, responder, template, responderPrivateKey)
|
||||
if err == nil {
|
||||
t.Fatal("CreateResponse didn't fail with non-valid template.IssuerHash value crypto.MD5")
|
||||
}
|
||||
|
||||
resp, err := ParseResponse(responseBytes, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
testCases := []struct {
|
||||
name string
|
||||
issuerHash crypto.Hash
|
||||
}{
|
||||
{"Zero value", 0},
|
||||
{"crypto.SHA1", crypto.SHA1},
|
||||
{"crypto.SHA256", crypto.SHA256},
|
||||
{"crypto.SHA384", crypto.SHA384},
|
||||
{"crypto.SHA512", crypto.SHA512},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
template.IssuerHash = tc.issuerHash
|
||||
responseBytes, err := CreateResponse(issuer, responder, template, responderPrivateKey)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateResponse failed: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resp.ThisUpdate, template.ThisUpdate) {
|
||||
t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, template.ThisUpdate)
|
||||
}
|
||||
resp, err := ParseResponse(responseBytes, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseResponse failed: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resp.NextUpdate, template.NextUpdate) {
|
||||
t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, template.NextUpdate)
|
||||
}
|
||||
if !reflect.DeepEqual(resp.ThisUpdate, template.ThisUpdate) {
|
||||
t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, template.ThisUpdate)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resp.RevokedAt, template.RevokedAt) {
|
||||
t.Errorf("resp.RevokedAt: got %d, want %d", resp.RevokedAt, template.RevokedAt)
|
||||
}
|
||||
if !reflect.DeepEqual(resp.NextUpdate, template.NextUpdate) {
|
||||
t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, template.NextUpdate)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(resp.Extensions, template.ExtraExtensions) {
|
||||
t.Errorf("resp.Extensions: got %v, want %v", resp.Extensions, template.ExtraExtensions)
|
||||
}
|
||||
if !reflect.DeepEqual(resp.RevokedAt, template.RevokedAt) {
|
||||
t.Errorf("resp.RevokedAt: got %d, want %d", resp.RevokedAt, template.RevokedAt)
|
||||
}
|
||||
|
||||
if !resp.ProducedAt.Equal(producedAt) {
|
||||
t.Errorf("resp.ProducedAt: got %d, want %d", resp.ProducedAt, producedAt)
|
||||
}
|
||||
if !reflect.DeepEqual(resp.Extensions, template.ExtraExtensions) {
|
||||
t.Errorf("resp.Extensions: got %v, want %v", resp.Extensions, template.ExtraExtensions)
|
||||
}
|
||||
|
||||
if resp.Status != template.Status {
|
||||
t.Errorf("resp.Status: got %d, want %d", resp.Status, template.Status)
|
||||
}
|
||||
delay := time.Since(resp.ProducedAt)
|
||||
if delay < -time.Hour || delay > time.Hour {
|
||||
t.Errorf("resp.ProducedAt: got %s, want close to current time (%s)", resp.ProducedAt, time.Now())
|
||||
}
|
||||
|
||||
if resp.SerialNumber.Cmp(template.SerialNumber) != 0 {
|
||||
t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, template.SerialNumber)
|
||||
}
|
||||
if resp.Status != template.Status {
|
||||
t.Errorf("resp.Status: got %d, want %d", resp.Status, template.Status)
|
||||
}
|
||||
|
||||
if resp.RevocationReason != template.RevocationReason {
|
||||
t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, template.RevocationReason)
|
||||
if resp.SerialNumber.Cmp(template.SerialNumber) != 0 {
|
||||
t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, template.SerialNumber)
|
||||
}
|
||||
|
||||
if resp.RevocationReason != template.RevocationReason {
|
||||
t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, template.RevocationReason)
|
||||
}
|
||||
|
||||
expectedHash := tc.issuerHash
|
||||
if tc.issuerHash == 0 {
|
||||
expectedHash = crypto.SHA1
|
||||
}
|
||||
|
||||
if resp.IssuerHash != expectedHash {
|
||||
t.Errorf("resp.IssuerHash: got %d, want %d", resp.IssuerHash, expectedHash)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,6 +343,21 @@ func TestOCSPDecodeMultiResponse(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestOCSPDecodeMultiResponseWithoutMatchingCert(t *testing.T) {
|
||||
wrongCert, _ := hex.DecodeString(startComHex)
|
||||
cert, err := x509.ParseCertificate(wrongCert)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
responseBytes, _ := hex.DecodeString(ocspMultiResponseHex)
|
||||
_, err = ParseResponseForCert(responseBytes, cert, nil)
|
||||
want := ParseError("no response matching the supplied certificate")
|
||||
if err != want {
|
||||
t.Errorf("err: got %q, want %q", err, want)
|
||||
}
|
||||
}
|
||||
|
||||
// This OCSP response was taken from Thawte's public OCSP responder.
|
||||
// To recreate:
|
||||
// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
|
||||
|
@ -354,6 +416,41 @@ const ocspResponseHex = "308206bc0a0100a08206b5308206b106092b0601050507300101048
|
|||
"a1d24ce16e41a9941568fec5b42771e118f16c106a54ccc339a4b02166445a167902e75e" +
|
||||
"6d8620b0825dcd18a069b90fd851d10fa8effd409deec02860d26d8d833f304b10669b42"
|
||||
|
||||
const startComResponderCertHex = "308204b23082039aa003020102020101300d06092a864886f70d010105050030818c310b" +
|
||||
"300906035504061302494c31163014060355040a130d5374617274436f6d204c74642e31" +
|
||||
"2b3029060355040b1322536563757265204469676974616c204365727469666963617465" +
|
||||
"205369676e696e67313830360603550403132f5374617274436f6d20436c617373203120" +
|
||||
"5072696d61727920496e7465726d65646961746520536572766572204341301e170d3037" +
|
||||
"313032353030323330365a170d3132313032333030323330365a304c310b300906035504" +
|
||||
"061302494c31163014060355040a130d5374617274436f6d204c74642e31253023060355" +
|
||||
"0403131c5374617274436f6d20436c6173732031204f435350205369676e657230820122" +
|
||||
"300d06092a864886f70d01010105000382010f003082010a0282010100b9561b4c453187" +
|
||||
"17178084e96e178df2255e18ed8d8ecc7c2b7b51a6c1c2e6bf0aa3603066f132fe10ae97" +
|
||||
"b50e99fa24b83fc53dd2777496387d14e1c3a9b6a4933e2ac12413d085570a95b8147414" +
|
||||
"a0bc007c7bcf222446ef7f1a156d7ea1c577fc5f0facdfd42eb0f5974990cb2f5cefebce" +
|
||||
"ef4d1bdc7ae5c1075c5a99a93171f2b0845b4ff0864e973fcfe32f9d7511ff87a3e94341" +
|
||||
"0c90a4493a306b6944359340a9ca96f02b66ce67f028df2980a6aaee8d5d5d452b8b0eb9" +
|
||||
"3f923cc1e23fcccbdbe7ffcb114d08fa7a6a3c404f825d1a0e715935cf623a8c7b596700" +
|
||||
"14ed0622f6089a9447a7a19010f7fe58f84129a2765ea367824d1c3bb2fda30853020301" +
|
||||
"0001a382015c30820158300c0603551d130101ff04023000300b0603551d0f0404030203" +
|
||||
"a8301e0603551d250417301506082b0601050507030906092b0601050507300105301d06" +
|
||||
"03551d0e0416041445e0a36695414c5dd449bc00e33cdcdbd2343e173081a80603551d23" +
|
||||
"0481a030819d8014eb4234d098b0ab9ff41b6b08f7cc642eef0e2c45a18181a47f307d31" +
|
||||
"0b300906035504061302494c31163014060355040a130d5374617274436f6d204c74642e" +
|
||||
"312b3029060355040b1322536563757265204469676974616c2043657274696669636174" +
|
||||
"65205369676e696e6731293027060355040313205374617274436f6d2043657274696669" +
|
||||
"636174696f6e20417574686f7269747982010a30230603551d12041c301a861868747470" +
|
||||
"3a2f2f7777772e737461727473736c2e636f6d2f302c06096086480186f842010d041f16" +
|
||||
"1d5374617274436f6d205265766f636174696f6e20417574686f72697479300d06092a86" +
|
||||
"4886f70d01010505000382010100182d22158f0fc0291324fa8574c49bb8ff2835085adc" +
|
||||
"bf7b7fc4191c397ab6951328253fffe1e5ec2a7da0d50fca1a404e6968481366939e666c" +
|
||||
"0a6209073eca57973e2fefa9ed1718e8176f1d85527ff522c08db702e3b2b180f1cbff05" +
|
||||
"d98128252cf0f450f7dd2772f4188047f19dc85317366f94bc52d60f453a550af58e308a" +
|
||||
"aab00ced33040b62bf37f5b1ab2a4f7f0f80f763bf4d707bc8841d7ad9385ee2a4244469" +
|
||||
"260b6f2bf085977af9074796048ecc2f9d48a1d24ce16e41a9941568fec5b42771e118f1" +
|
||||
"6c106a54ccc339a4b02166445a167902e75e6d8620b0825dcd18a069b90fd851d10fa8ef" +
|
||||
"fd409deec02860d26d8d833f304b10669b42"
|
||||
|
||||
const startComHex = "308206343082041ca003020102020118300d06092a864886f70d0101050500307d310b30" +
|
||||
"0906035504061302494c31163014060355040a130d5374617274436f6d204c74642e312b" +
|
||||
"3029060355040b1322536563757265204469676974616c20436572746966696361746520" +
|
||||
|
|
|
@ -307,8 +307,6 @@ func readToNextPublicKey(packets *packet.Reader) (err error) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// ReadEntity reads an entity (public key, identities, subkeys etc) from the
|
||||
|
|
|
@ -300,7 +300,7 @@ func TestNewEntityWithoutPreferredHash(t *testing.T) {
|
|||
|
||||
for _, identity := range entity.Identities {
|
||||
if len(identity.SelfSignature.PreferredHash) != 0 {
|
||||
t.Fatal("Expected preferred hash to be empty but got length %d", len(identity.SelfSignature.PreferredHash))
|
||||
t.Fatalf("Expected preferred hash to be empty but got length %d", len(identity.SelfSignature.PreferredHash))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,8 +273,6 @@ func consumeAll(r io.Reader) (n int64, err error) {
|
|||
return
|
||||
}
|
||||
}
|
||||
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// packetType represents the numeric ids of the different OpenPGP packet types. See
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue