mirror of
https://github.com/FiloSottile/age.git
synced 2026-08-28 03:46:52 +00:00
tests: finish parsing and X25519 tests, distinguish HMAC errors
If the implementation re-encodes the header before checking the HMAC, that would mask malleability issues: the HMAC check would fail because the tests HMAC'd the original header, but an attacker could also produce the right HMAC. Instead of duplicating every parsing tests (with the original and re-encoded HMAC), we make the test framework distinguish HMAC errors, which ensures bad encodings are recognized as such and not bypassable HMAC errors.
This commit is contained in:
@@ -258,7 +258,7 @@ func Parse(input io.Reader) (*Header, io.Reader, error) {
|
||||
return nil, nil, errorf("malformed closing line: %q", line)
|
||||
}
|
||||
h.MAC, err = DecodeString(args[0])
|
||||
if err != nil {
|
||||
if err != nil || len(h.MAC) != 32 {
|
||||
return nil, nil, errorf("malformed closing line %q: %v", line, err)
|
||||
}
|
||||
break
|
||||
|
||||
+28
-10
@@ -106,16 +106,22 @@ func (f *TestFile) Body(body []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (f *TestFile) Stanza(args []string, body []byte) {
|
||||
f.ArgsLine(args...)
|
||||
f.Body(body)
|
||||
}
|
||||
|
||||
func (f *TestFile) AEADBody(key, body []byte) {
|
||||
aead, _ := chacha20poly1305.New(key)
|
||||
f.Body(aead.Seal(nil, make([]byte, chacha20poly1305.NonceSize), body, nil))
|
||||
}
|
||||
|
||||
func x25519(scalar, point []byte) []byte {
|
||||
secret, err := curve25519.X25519(scalar, point)
|
||||
if err != nil {
|
||||
if err.Error() == "bad input point: low order point" {
|
||||
return make([]byte, 32)
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
return secret
|
||||
}
|
||||
|
||||
func (f *TestFile) X25519(identity []byte) {
|
||||
f.X25519RecordIdentity(identity)
|
||||
f.X25519NoRecordIdentity(identity)
|
||||
@@ -127,11 +133,16 @@ func (f *TestFile) X25519RecordIdentity(identity []byte) {
|
||||
}
|
||||
|
||||
func (f *TestFile) X25519NoRecordIdentity(identity []byte) {
|
||||
recipient, _ := curve25519.X25519(identity, curve25519.Basepoint)
|
||||
ephemeral := f.Rand(32)
|
||||
share, _ := curve25519.X25519(ephemeral, curve25519.Basepoint)
|
||||
share := x25519(f.Rand(32), curve25519.Basepoint)
|
||||
f.X25519Stanza(share, identity)
|
||||
}
|
||||
|
||||
func (f *TestFile) X25519Stanza(share, identity []byte) {
|
||||
recipient := x25519(identity, curve25519.Basepoint)
|
||||
f.ArgsLine("X25519", b64(share))
|
||||
secret, _ := curve25519.X25519(ephemeral, recipient)
|
||||
// This would be ordinarily done as [ephemeral]recipient rather than
|
||||
// [identity]share, but for some tests we don't have the dlog of share.
|
||||
secret := x25519(identity, share)
|
||||
key := make([]byte, 32)
|
||||
hkdf.New(sha256.New, secret, append(share, recipient...),
|
||||
[]byte("age-encryption.org/v1/X25519")).Read(key)
|
||||
@@ -150,8 +161,11 @@ func (f *TestFile) ScryptRecordPassphrase(passphrase string) {
|
||||
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...),
|
||||
key, err := scrypt.Key([]byte(passphrase), append([]byte("age-encryption.org/v1/scrypt"), salt...),
|
||||
1<<workFactor, 8, 1, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
f.AEADBody(key, f.fileKey)
|
||||
}
|
||||
|
||||
@@ -201,6 +215,10 @@ func (f *TestFile) ExpectPayloadFailure() {
|
||||
f.expect = "payload failure"
|
||||
}
|
||||
|
||||
func (f *TestFile) ExpectHMACFailure() {
|
||||
f.expect = "HMAC failure"
|
||||
}
|
||||
|
||||
func (f *TestFile) Comment(c string) {
|
||||
f.comment = c
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
expect: header failure
|
||||
expect: HMAC failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1EGTZVFFV20835NWYV6270LXYVK2VKNX2MMDKWYKLMGR48UAWX40Q2P2LM0
|
||||
|
||||
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-- stanza
|
||||
|
||||
--- lpxzkyQGe/sA7F1yh4c6KVZV7//jANm5lYefTToioXs
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-> stanza
|
||||
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
|
||||
QUE=
|
||||
--- OtG7IuNHaf2SHZuowmxg/fhbhtz0/DI5g5OGd7WH7S0
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-> stanza argument
|
||||
|
||||
--- bosBxVRBzKF9emyxQ9BERq7+D5JKU+lvbEsL8UHJ/SA
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
+2
-1
@@ -8,6 +8,7 @@ age-encryption.org/v1
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-> stanza
|
||||
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
|
||||
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
|
||||
|
||||
--- +3PC416gxa7Mk7WxpX0kb6DVfSuCun0niGre+G4bZhE
|
||||
--- cb4SqtunSJzXKDGjqeYxuva9Be80QXEDKDn2aKBaCsw
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-> stanza è
|
||||
|
||||
--- sTIB/0Fc74rhpjC4RAxoR3E01eVTTnWruaD+c5QWjKI
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
comment: a body line is longer than 64 columns
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-> stanza
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
|
||||
--- tnRUR2vmmU92czsjnioF5ujgXUetUhzUoQPPGT9wmug
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
->
|
||||
|
||||
--- B0qjnUjVajTa8I4Uia49g1c4DMQQN6u9m9QOSS1HLks
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-> stanza
|
||||
QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB
|
||||
QUF
|
||||
--- nQM2VCzmNLPrUurNWN+SW9wVp/9uTMQ/6CTUM7l8c84
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-> stanza
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
--- MZaFAh8ldzU0F88NJjLx5yd7fnd57XS5COowmgvQtXQ
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1234
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
--- 38AL8Mr4VwmS6CNbM4bc7u3WwGBDqsMTRHOuYJ9ckqs
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
comment: the ChaCha20Poly1305 authentication tag on the body of the X25519 stanza is wrong
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw0o
|
||||
--- tG0k9bg4iIuBdMWb13n7FFYDzoBbtsLppNLhbh22aKg
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
expect: success
|
||||
payload: 013f54400c82da08037759ada907a8b864e97de81c088a182062c4b5622fd2ab
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
|
||||
age-encryption.org/v1
|
||||
-> grease
|
||||
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
-> grease
|
||||
|
||||
--- 7NLrfbRUZt6qK0pdtARUf59dHwo12ReldjJKjMlbE3I
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1EGTZVFFV20835NWYV6270LXYVK2VKNX2MMDKWYKLMGR48UAWX40Q2P2LM0
|
||||
comment: a trailing zero is missing from the X25519 share
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCcA
|
||||
hjabGXwSLQ9c3S6Lw2i+S2Tu2fiwQHHslbBN6B41FLE
|
||||
--- QbEwdWirchS37UUOPh7uVddRiOaWjFwRUpaQ4Q+Z1RE
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1XMWWC06LY3EE5RYTXM9MFLAZ2U56JJJ36S0MYPDRWSVLUL66MV4QX3S7F6
|
||||
comment: the first argument in the X25519 stanza is lowercase
|
||||
|
||||
age-encryption.org/v1
|
||||
-> x25519 TEiF0ypqr+bpvcqXNyCVJpL7OuwPdVwPL7KQEbFDOCc
|
||||
EmECAEcKN+n/Vs9SbWiV+Hu0r+E8R77DdWYyd83nw7U
|
||||
--- SwXKO3dXLh9l5QiSgMWgPhCkwstT8oB4jLDv7aBgC+c
|
||||
îÏbÇΑ´3'NhÔòùL·L[þ÷¾ªRÈð¼™,ƒ1ûf
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
expect: header failure
|
||||
file key: 59454c4c4f57205355424d4152494e45
|
||||
identity: AGE-SECRET-KEY-1EGTZVFFV20835NWYV6270LXYVK2VKNX2MMDKWYKLMGR48UAWX40Q2P2LM0
|
||||
comment: a trailing zero is missing from the X25519 share
|
||||
|
||||
age-encryption.org/v1
|
||||
-> X25519 l7o4oTX9X5E3/KODa/7CQ0CrA9fKMWsm9IJjYzSlJg
|
||||
yUGP5aPob6YJ+vzRfBtDT9D1K/wmyheZE/Xl/mDSKA4
|
||||
--- Zn1/VRtHpD93HtIXSv1S++POXeKcQF7w1+hpXhMiAbk
|
||||
¬]?7åPqÓ¦ F—¹ •Â÷õÛ®è
zŒ(rŠóÎ|
|
||||
+20
-15
@@ -75,10 +75,9 @@ func TestVectors(t *testing.T) {
|
||||
|
||||
func testVector(t *testing.T, test []byte) {
|
||||
var (
|
||||
expectHeaderFailure bool
|
||||
expectPayloadFailure bool
|
||||
payloadHash *[32]byte
|
||||
identities []age.Identity
|
||||
expect string
|
||||
payloadHash *[32]byte
|
||||
identities []age.Identity
|
||||
)
|
||||
|
||||
for {
|
||||
@@ -95,13 +94,13 @@ func testVector(t *testing.T, test []byte) {
|
||||
case "expect":
|
||||
switch value {
|
||||
case "success":
|
||||
case "HMAC failure":
|
||||
case "header failure":
|
||||
expectHeaderFailure = true
|
||||
case "payload failure":
|
||||
expectPayloadFailure = true
|
||||
default:
|
||||
t.Fatal("invalid test file: unknown expect value:", value)
|
||||
}
|
||||
expect = value
|
||||
case "payload":
|
||||
h, err := hex.DecodeString(value)
|
||||
if err != nil {
|
||||
@@ -130,24 +129,30 @@ func testVector(t *testing.T, test []byte) {
|
||||
}
|
||||
|
||||
r, err := age.Decrypt(bytes.NewReader(test), identities...)
|
||||
if err != nil {
|
||||
if expectHeaderFailure {
|
||||
if err != nil && strings.HasSuffix(err.Error(), "bad header MAC") {
|
||||
if expect == "HMAC failure" {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
t.Fatal("unexpected header error:", err)
|
||||
} else if expectHeaderFailure {
|
||||
t.Fatal("expected header error")
|
||||
t.Fatalf("expected %s, got HMAC error", expect)
|
||||
} else if err != nil {
|
||||
if expect == "header failure" {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
t.Fatalf("expected %s, got: %v", expect, err)
|
||||
} else if expect != "success" && expect != "payload failure" {
|
||||
t.Fatalf("expected %s, got success", expect)
|
||||
}
|
||||
out, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
if expectPayloadFailure {
|
||||
if expect == "payload failure" {
|
||||
t.Log(err)
|
||||
return
|
||||
}
|
||||
t.Fatal("unexpected payload error:", err)
|
||||
} else if expectPayloadFailure {
|
||||
t.Fatal("expected payload error")
|
||||
t.Fatalf("expected %s, got: %v", expect, err)
|
||||
} else if expect != "success" {
|
||||
t.Fatalf("expected %s, got success", expect)
|
||||
}
|
||||
if sha256.Sum256(out) != *payloadHash {
|
||||
t.Error("payload hash mismatch")
|
||||
|
||||
+1
-1
@@ -16,6 +16,6 @@ func main() {
|
||||
f.HMAC()
|
||||
f.FileKey(testkit.TestFileKey)
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.ExpectHMACFailure()
|
||||
f.Generate()
|
||||
}
|
||||
|
||||
@@ -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.X25519(testkit.TestX25519Recipient)
|
||||
f.TextLine("-- stanza")
|
||||
f.Body([]byte(""))
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Generate()
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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 (
|
||||
"bytes"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine("stanza")
|
||||
f.Body(bytes.Repeat([]byte("A"), 50))
|
||||
f.TextLine(f.UnreadLine() + "=")
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Generate()
|
||||
}
|
||||
@@ -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.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine("stanza", "", "argument")
|
||||
f.Body([]byte(""))
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Generate()
|
||||
}
|
||||
@@ -17,7 +17,7 @@ func main() {
|
||||
f.VersionLine("v1")
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine("stanza")
|
||||
f.Body(bytes.Repeat([]byte("A"), 48))
|
||||
f.Body(bytes.Repeat([]byte("A"), 48*2))
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.Generate()
|
||||
|
||||
@@ -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.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine("stanza", "è")
|
||||
f.Body([]byte(""))
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Generate()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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 (
|
||||
"strings"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine("stanza")
|
||||
f.TextLine(strings.Repeat("A", 68))
|
||||
f.TextLine("")
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Comment("a body line is longer than 64 columns")
|
||||
f.Generate()
|
||||
}
|
||||
@@ -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.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine()
|
||||
f.Body([]byte(""))
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Generate()
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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 (
|
||||
"bytes"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine("stanza")
|
||||
f.Body(bytes.Repeat([]byte("A"), 50))
|
||||
f.TextLine(testkit.NotCanonicalBase64(f.UnreadLine()))
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Generate()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// 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 (
|
||||
"strings"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine("stanza")
|
||||
f.TextLine(strings.Repeat("A", 32) + "\r" + strings.Repeat("A", 31))
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Generate()
|
||||
}
|
||||
@@ -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("v1234")
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Generate()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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 (
|
||||
"encoding/base64"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
body, _ := base64.RawStdEncoding.DecodeString(f.UnreadLine())
|
||||
body[len(body)-1] ^= 0xff
|
||||
f.TextLine(base64.RawStdEncoding.EncodeToString(body))
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Comment("the ChaCha20Poly1305 authentication tag on the body of the X25519 stanza is wrong")
|
||||
f.Generate()
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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("grease")
|
||||
f.Body(nil)
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
f.ArgsLine("grease")
|
||||
f.Body(nil)
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.Generate()
|
||||
}
|
||||
@@ -6,26 +6,14 @@
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
import "filippo.io/age/internal/testkit"
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
f.X25519RecordIdentity(testkit.TestX25519Identity)
|
||||
share := make([]byte, curve25519.PointSize)
|
||||
f.ArgsLine("X25519", base64.RawStdEncoding.EncodeToString(share))
|
||||
secret := make([]byte, curve25519.PointSize)
|
||||
key := make([]byte, 32)
|
||||
hkdf.New(sha256.New, secret, append(share, testkit.TestX25519Recipient...),
|
||||
[]byte("age-encryption.org/v1/X25519")).Read(key)
|
||||
f.AEADBody(key, testkit.TestFileKey)
|
||||
share := make([]byte, 32)
|
||||
f.X25519Stanza(share, testkit.TestX25519Identity)
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// 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 (
|
||||
"encoding/base64"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
share, _ := curve25519.X25519(f.Rand(32), curve25519.Basepoint)
|
||||
f.X25519RecordIdentity(testkit.TestX25519Identity)
|
||||
f.X25519Stanza(share, testkit.TestX25519Identity)
|
||||
body, _ := f.UnreadLine(), f.UnreadLine()
|
||||
f.TextLine("-> X25519 " + base64.RawStdEncoding.EncodeToString(append(share, 0x00)))
|
||||
f.TextLine(body)
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Comment("a trailing zero is missing from the X25519 share")
|
||||
f.Generate()
|
||||
}
|
||||
@@ -6,14 +6,7 @@
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
import "filippo.io/age/internal/testkit"
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
@@ -24,12 +17,7 @@ func main() {
|
||||
share := []byte{0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24, 0xb1, 0xd0,
|
||||
0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b, 0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c,
|
||||
0x8e, 0x86, 0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0xd7}
|
||||
f.ArgsLine("X25519", base64.RawStdEncoding.EncodeToString(share))
|
||||
secret := make([]byte, curve25519.PointSize)
|
||||
key := make([]byte, 32)
|
||||
hkdf.New(sha256.New, secret, append(share, testkit.TestX25519Recipient...),
|
||||
[]byte("age-encryption.org/v1/X25519")).Read(key)
|
||||
f.AEADBody(key, testkit.TestFileKey)
|
||||
f.X25519Stanza(share, testkit.TestX25519Identity)
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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 (
|
||||
"strings"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
f.X25519(testkit.TestX25519Recipient)
|
||||
body, args := f.UnreadLine(), f.UnreadLine()
|
||||
f.TextLine(strings.Replace(args, "X25519", "x25519", -1))
|
||||
f.TextLine(body)
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Comment("the first argument in the X25519 stanza is lowercase")
|
||||
f.Generate()
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// 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 (
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
|
||||
"filippo.io/age/internal/testkit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
f := testkit.NewTestFile()
|
||||
f.VersionLine("v1")
|
||||
share, _ := hex.DecodeString("97ba38a135fd5f9137fca3836bfec24340ab03d7ca316b26f482636334a52600")
|
||||
f.X25519RecordIdentity(testkit.TestX25519Identity)
|
||||
f.X25519Stanza(share, testkit.TestX25519Identity)
|
||||
body, _ := f.UnreadLine(), f.UnreadLine()
|
||||
f.TextLine("-> X25519 " + base64.RawStdEncoding.EncodeToString(share[:31]))
|
||||
f.TextLine(body)
|
||||
f.HMAC()
|
||||
f.Payload("age")
|
||||
f.ExpectHeaderFailure()
|
||||
f.Comment("a trailing zero is missing from the X25519 share")
|
||||
f.Generate()
|
||||
}
|
||||
Reference in New Issue
Block a user