tests: add scrypt tests and move Go files from testdata

This commit is contained in:
Filippo Valsorda 2022-06-15 20:16:36 +02:00
parent 787044bdb6
commit 92713afd1e
45 changed files with 186 additions and 14 deletions

2
.gitattributes vendored
View file

@ -1,2 +1,2 @@
*.age binary
*.test binary
testdata/testkit/* binary

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -12,6 +12,7 @@ import (
"fmt"
"io"
"os"
"strconv"
"strings"
"filippo.io/age/internal/bech32"
@ -19,6 +20,7 @@ import (
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/hkdf"
"golang.org/x/crypto/scrypt"
)
var TestFileKey = []byte("YELLOW SUBMARINE")
@ -32,13 +34,14 @@ type TestFile struct {
Buf bytes.Buffer
Rand func(n int) []byte
fileKey []byte
streamKey []byte
nonce [12]byte
payload bytes.Buffer
expect string
comment string
identities []string
fileKey []byte
streamKey []byte
nonce [12]byte
payload bytes.Buffer
expect string
comment string
identities []string
passphrases []string
}
func NewTestFile() *TestFile {
@ -117,6 +120,23 @@ func (f *TestFile) X25519NoRecordIdentity(identity []byte) {
f.AEADBody(key, f.fileKey)
}
func (f *TestFile) Scrypt(passphrase string, workFactor int) {
f.ScryptRecordPassphrase(passphrase)
f.ScryptNoRecordPassphrase(passphrase, workFactor)
}
func (f *TestFile) ScryptRecordPassphrase(passphrase string) {
f.passphrases = append(f.passphrases, passphrase)
}
func (f *TestFile) ScryptNoRecordPassphrase(passphrase string, workFactor int) {
salt := f.Rand(16)
f.ArgsLine("scrypt", b64(salt), strconv.Itoa(workFactor))
key, _ := scrypt.Key([]byte(passphrase), append([]byte("age-encryption.org/v1/scrypt"), salt...),
1<<workFactor, 8, 1, 32)
f.AEADBody(key, f.fileKey)
}
func (f *TestFile) HMACLine(h []byte) {
f.TextLine("--- " + b64(h))
}
@ -176,6 +196,9 @@ func (f *TestFile) Generate() {
for _, id := range f.identities {
fmt.Printf("identity: %s\n", id)
}
for _, p := range f.passphrases {
fmt.Printf("passphrase: %s\n", p)
}
if f.comment != "" {
fmt.Printf("comment: %s\n", f.comment)
}

BIN
testdata/testkit/long_file_key_scrypt vendored Normal file

Binary file not shown.

BIN
testdata/testkit/scrypt vendored Normal file

Binary file not shown.

BIN
testdata/testkit/scrypt_and_x25519 vendored Normal file

Binary file not shown.

BIN
testdata/testkit/scrypt_no_match vendored Normal file

Binary file not shown.

BIN
testdata/testkit/scrypt_work_factor_23 vendored Normal file

Binary file not shown.

BIN
testdata/testkit/valid_characters vendored Normal file

Binary file not shown.

Binary file not shown.

View file

@ -27,19 +27,20 @@ func TestMain(m *testing.M) {
flag.Parse()
if *genFlag {
log.SetFlags(0)
tests, err := filepath.Glob("testdata/*.test")
tests, err := filepath.Glob("testdata/testkit/*")
if err != nil {
log.Fatal(err)
}
for _, test := range tests {
os.Remove(test)
}
generators, err := filepath.Glob("testdata/*.go")
generators, err := filepath.Glob("tests/*.go")
if err != nil {
log.Fatal(err)
}
for _, generator := range generators {
vector := strings.TrimSuffix(generator, ".go") + ".test"
vector := strings.TrimSuffix(generator, ".go")
vector = "testdata/testkit/" + strings.TrimPrefix(vector, "tests/")
log.Printf("%s -> %s\n", generator, vector)
out, err := exec.Command("go", "run", generator).Output()
if err != nil {
@ -56,7 +57,7 @@ func TestMain(m *testing.M) {
}
func TestVectors(t *testing.T) {
tests, err := filepath.Glob("testdata/*.test")
tests, err := filepath.Glob("testdata/testkit/*")
if err != nil {
log.Fatal(err)
}
@ -65,8 +66,7 @@ func TestVectors(t *testing.T) {
if err != nil {
t.Fatal(err)
}
name := strings.TrimPrefix(test, "testdata/")
name = strings.TrimSuffix(name, ".test")
name := strings.TrimPrefix(test, "testdata/testkit/")
t.Run(name, func(t *testing.T) {
testVector(t, contents)
})
@ -114,6 +114,12 @@ func testVector(t *testing.T, test []byte) {
t.Fatal(err)
}
identities = append(identities, i)
case "passphrase":
i, err := age.NewScryptIdentity(value)
if err != nil {
t.Fatal(err)
}
identities = append(identities, i)
case "file key":
// Ignored.
case "comment":

View file

@ -0,0 +1,21 @@
// Copyright 2022 The age Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
import "filippo.io/age/internal/testkit"
func main() {
f := testkit.NewTestFile()
f.FileKey([]byte("A LONGER YELLOW SUBMARINE"))
f.VersionLine("v1")
f.Scrypt("password", 10)
f.HMAC()
f.Payload("age")
f.ExpectHeaderFailure()
f.Comment("the file key must be checked to be 16 bytes before decrypting it")
f.Generate()
}

18
tests/scrypt.go Normal file
View file

@ -0,0 +1,18 @@
// Copyright 2022 The age Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
import "filippo.io/age/internal/testkit"
func main() {
f := testkit.NewTestFile()
f.VersionLine("v1")
f.Scrypt("password", 10)
f.HMAC()
f.Payload("age")
f.Generate()
}

View file

@ -0,0 +1,21 @@
// Copyright 2022 The age Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
import "filippo.io/age/internal/testkit"
func main() {
f := testkit.NewTestFile()
f.VersionLine("v1")
f.X25519NoRecordIdentity(testkit.TestX25519Identity)
f.Scrypt("password", 10)
f.HMAC()
f.Payload("age")
f.ExpectHeaderFailure()
f.Comment("scrypt stanzas must be alone in the header")
f.Generate()
}

20
tests/scrypt_no_match.go Normal file
View file

@ -0,0 +1,20 @@
// Copyright 2022 The age Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
import "filippo.io/age/internal/testkit"
func main() {
f := testkit.NewTestFile()
f.VersionLine("v1")
f.ScryptRecordPassphrase("wrong")
f.ScryptNoRecordPassphrase("password", 10)
f.HMAC()
f.Payload("age")
f.ExpectHeaderFailure()
f.Generate()
}

View file

@ -0,0 +1,23 @@
// Copyright 2022 The age Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
import "filippo.io/age/internal/testkit"
func main() {
f := testkit.NewTestFile()
f.VersionLine("v1")
// Hardcoded because it would be too slow to regenerate every time.
// f.Scrypt("password", 23)
f.ArgsLine("scrypt", "rF0/NwblUHHTpgQgRpe5CQ", "23")
f.TextLine("qW9eVsT0NVb/Vswtw8kPIxUnaYmm9Px1dYmq2+4+qZA")
f.HMAC()
f.Payload("age")
f.ExpectHeaderFailure()
f.Comment("work factor is very high, would take a long time to compute")
f.Generate()
}

21
tests/valid_characters.go Normal file
View file

@ -0,0 +1,21 @@
// Copyright 2022 The age Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
import "filippo.io/age/internal/testkit"
func main() {
f := testkit.NewTestFile()
f.VersionLine("v1")
f.ArgsLine("!\"#$%&'", "()*+,-./", "01234567", "89:;<=>?", "@ABCDEFG",
"HIJKLMNO", "PQRSTUVW", "XYZ[\\]^_", "`abcdefg", "hijklmno", "pqrstuvw", "xyz{|}~")
f.Body([]byte(""))
f.X25519(testkit.TestX25519Recipient)
f.HMAC()
f.Payload("age")
f.Generate()
}

View file

@ -0,0 +1,19 @@
// Copyright 2022 The age Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
package main
import "filippo.io/age/internal/testkit"
func main() {
f := testkit.NewTestFile()
f.VersionLine("v1")
f.X25519NoRecordIdentity(f.Rand(32))
f.X25519(testkit.TestX25519Recipient)
f.HMAC()
f.Payload("age")
f.Generate()
}