Skip to content

Commit 2f9b08e

Browse files
committed
XAES-256-GCM: add test vectors
1 parent bb44e18 commit 2f9b08e

File tree

4 files changed

+157
-0
lines changed

4 files changed

+157
-0
lines changed

XAES-256-GCM.md

+58
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,63 @@ The algorithm maps to [NIST SP 800-38B] and [NIST SP 800-108r1] as follows:
9696
* Step 5 applies the CMAC PRF twice to the two single-block messages to derive
9797
the KDF output according to [NIST SP 800-38B, Section 6.2].
9898

99+
## Test vectors
100+
101+
In the following vectors, unquoted values are hex-encoded, and quoted values are
102+
ASCII strings.
103+
104+
K: 0101010101010101010101010101010101010101010101010101010101010101
105+
N: "ABCDEFGHIJKLMNOPQRSTUVWX"
106+
107+
L: 7298caa565031eadc6ce23d23ea66378
108+
K1: e531954aca063d5b8d9c47a47d4cc6f0
109+
M1: 000158004142434445464748494a4b4c
110+
M2: 000258004142434445464748494a4b4c
111+
Kₓ: c8612c9ed53fe43e8e005b828a1631a0bbcb6ab2f46514ec4f439fcfd0fa969b
112+
Nₓ: 4d4e4f505152535455565758
113+
114+
Plaintext: "XAES-256-GCM"
115+
AAD: ""
116+
Ciphertext: ce546ef63c9cc60765923609b33a9a1974e96e52daf2fcf7075e2271
117+
118+
In the previous vector MSB₁(*L*) = 0, while in the following vector MSB₁ = 1.
119+
120+
K: 0303030303030303030303030303030303030303030303030303030303030303
121+
N: "ABCDEFGHIJKLMNOPQRSTUVWX"
122+
123+
L: 91c08762876dccf9ba204a33768fa5fe
124+
K1: 23810ec50edb99f374409466ed1f4b7b
125+
M1: 000158004142434445464748494a4b4c
126+
M2: 000258004142434445464748494a4b4c
127+
Kₓ: e9c621d4cdd9b11b00a6427ad7e559aeedd66b3857646677748f8ca796cb3fd8
128+
Nₓ: 4d4e4f505152535455565758
129+
130+
Plaintext: "XAES-256-GCM"
131+
AAD: "c2sp.org/XAES-256-GCM"
132+
Ciphertext: 986ec1832593df5443a179437fd083bf3fdb41abd740a21f71eb769d
133+
134+
### Accumulated randomized tests
135+
136+
For each test, the following structure (presented according to [RFC 8446,
137+
Section 3]) is read from a deterministic RNG, and the ciphertext is hashed.
138+
139+
The deterministic RNG is a single SHAKE-128 instance with an empty input. (The
140+
RNG stream starts with `7f9c2ba4e88f827d616045507605853e`.) The hash is a
141+
separate SHAKE-128 instance.
142+
143+
opaque key[32];
144+
opaque nonce[24];
145+
opaque plaintext<0..255>;
146+
opaque aad<0..255>;
147+
148+
The resulting hash for 10 000 iterations is
149+
150+
e6b9edf2df6cec60c8cbd864e2211b597fb69a529160cd040d56c0c210081939
151+
152+
The resulting hash for 1 000 000 iterations is
153+
154+
2163ae1445985a30b60585ee67daa55674df06901b890593e824b8a7c885ab15
155+
99156
## Alternatives
100157

101158
The goal of this design is to provide an AES-based AEAD with safely randomizable
@@ -191,4 +248,5 @@ derivation.
191248
[reduced-round variant]: https://words.filippo.io/dispatches/xaes-256-gcm-11/
192249
[AEGIS]: https://datatracker.ietf.org/doc/draft-irtf-cfrg-aegis-aead/
193250
[RFC 8452, Section 9]: https://www.rfc-editor.org/rfc/rfc8452.html#section-9
251+
[RFC 8446, Section 3]: https://www.rfc-editor.org/rfc/rfc8446.html#section-3
194252
[Double-Nonce-Derive-Key-GCM]: https://iacr.org/submit/files/slides/2024/rwc/rwc2024/105/slides.pdf

XAES-256-GCM/go/XAES-256-GCM_test.go

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package xaes256gcm_test
2+
3+
import (
4+
"bytes"
5+
"encoding/hex"
6+
"testing"
7+
8+
"xaes256gcm"
9+
10+
"golang.org/x/crypto/sha3"
11+
)
12+
13+
func TestVectors(t *testing.T) {
14+
key := bytes.Repeat([]byte{0x01}, xaes256gcm.KeySize)
15+
nonce := []byte("ABCDEFGHIJKLMNOPQRSTUVWX")
16+
plaintext := []byte("XAES-256-GCM")
17+
c, err := xaes256gcm.New(key)
18+
if err != nil {
19+
t.Fatal(err)
20+
}
21+
ciphertext := c.Seal(nil, nonce, plaintext, nil)
22+
expected := "ce546ef63c9cc60765923609b33a9a1974e96e52daf2fcf7075e2271"
23+
if got := hex.EncodeToString(ciphertext); got != expected {
24+
t.Errorf("got: %s", got)
25+
}
26+
if decrypted, err := c.Open(nil, nonce, ciphertext, nil); err != nil {
27+
t.Fatal(err)
28+
} else if !bytes.Equal(plaintext, decrypted) {
29+
t.Errorf("plaintext and decrypted are not equal")
30+
}
31+
32+
key = bytes.Repeat([]byte{0x03}, xaes256gcm.KeySize)
33+
aad := []byte("c2sp.org/XAES-256-GCM")
34+
c, err = xaes256gcm.New(key)
35+
if err != nil {
36+
t.Fatal(err)
37+
}
38+
ciphertext = c.Seal(nil, nonce, plaintext, aad)
39+
expected = "986ec1832593df5443a179437fd083bf3fdb41abd740a21f71eb769d"
40+
if got := hex.EncodeToString(ciphertext); got != expected {
41+
t.Errorf("got: %s", got)
42+
}
43+
if decrypted, err := c.Open(nil, nonce, ciphertext, aad); err != nil {
44+
t.Fatal(err)
45+
} else if !bytes.Equal(plaintext, decrypted) {
46+
t.Errorf("plaintext and decrypted are not equal")
47+
}
48+
}
49+
50+
func TestAccumulated(t *testing.T) {
51+
iterations := 10_000
52+
expected := "e6b9edf2df6cec60c8cbd864e2211b597fb69a529160cd040d56c0c210081939"
53+
if !testing.Short() {
54+
iterations = 1_000_000
55+
expected = "2163ae1445985a30b60585ee67daa55674df06901b890593e824b8a7c885ab15"
56+
}
57+
58+
s, d := sha3.NewShake128(), sha3.NewShake128()
59+
for i := 0; i < iterations; i++ {
60+
key := make([]byte, xaes256gcm.KeySize)
61+
s.Read(key)
62+
nonce := make([]byte, xaes256gcm.NonceSize)
63+
s.Read(nonce)
64+
lenByte := make([]byte, 1)
65+
s.Read(lenByte)
66+
plaintext := make([]byte, int(lenByte[0]))
67+
s.Read(plaintext)
68+
s.Read(lenByte)
69+
aad := make([]byte, int(lenByte[0]))
70+
s.Read(aad)
71+
72+
c, err := xaes256gcm.New(key)
73+
if err != nil {
74+
t.Fatal(err)
75+
}
76+
ciphertext := c.Seal(nil, nonce, plaintext, aad)
77+
decrypted, err := c.Open(nil, nonce, ciphertext, aad)
78+
if err != nil {
79+
t.Fatal(err)
80+
}
81+
if !bytes.Equal(plaintext, decrypted) {
82+
t.Errorf("plaintext and decrypted are not equal")
83+
}
84+
85+
d.Write(ciphertext)
86+
}
87+
if got := hex.EncodeToString(d.Sum(nil)); got != expected {
88+
t.Errorf("got: %s", got)
89+
}
90+
}

XAES-256-GCM/go/go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
module xaes256gcm
22

33
go 1.20
4+
5+
// Testing dependency.
6+
require golang.org/x/crypto v0.23.0
7+
8+
require golang.org/x/sys v0.20.0 // indirect

XAES-256-GCM/go/go.sum

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
2+
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
3+
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
4+
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

0 commit comments

Comments
 (0)