Freeze the Go implementation as a test-only oracle, with vectors
oracle/go is the Go code at 4c1507c, moved unchanged, plus test-only
generators that record what it computes. tests/vectors holds the
deterministic crypto/store vectors and synthetic fixtures they produce.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# Go oracle (test-only)
|
||||
|
||||
`oracle/go` is a frozen copy of the Go implementation of vault, taken from
|
||||
commit `4c1507c` ("Add unlock --idle, and packaging/repo.sh for
|
||||
repo.dixon.cx"), the last Go release on `master`. It is kept as the
|
||||
reference that the Rust implementation is checked against. It is **not**
|
||||
part of the shipped product: release builds, packages and the `vault`
|
||||
binary contain no Go code and need no Go toolchain.
|
||||
|
||||
Provenance:
|
||||
|
||||
- Every file under `oracle/go` is byte-identical to the same path at the
|
||||
repository root at `4c1507c`, except the three added test files below.
|
||||
- `oracle_vectors_test.go`, `internal/pqcrypt/oracle_vectors_test.go` and
|
||||
`internal/stream/oracle_vectors_test.go` are test-only generators. They
|
||||
call the frozen code and write what it computes; they skip themselves
|
||||
unless `VAULT_ORACLE_OUT` is set, and add nothing to the oracle binary.
|
||||
- Dependencies are pinned by `go.mod`/`go.sum`: CIRCL v1.6.4,
|
||||
golang.org/x/crypto v0.53.0, x/sys v0.46.0, x/term v0.44.0. The module
|
||||
needs Go 1.26.6 or newer.
|
||||
|
||||
Check the copy is still faithful:
|
||||
|
||||
```sh
|
||||
git diff --stat 4c1507c HEAD -M -- oracle/go # renames only, plus the generators
|
||||
```
|
||||
|
||||
Use:
|
||||
|
||||
```sh
|
||||
oracle/gen-vectors.sh # rewrite tests/vectors from the oracle
|
||||
(cd oracle/go && go build -o ../../target/vault-go .) # build the oracle CLI
|
||||
(cd oracle/go && go test ./...) # its own test-suite
|
||||
```
|
||||
|
||||
`cargo test` builds the oracle binary itself for the interoperability tests
|
||||
when `go` is on `PATH` (or uses `$VAULT_GO_ORACLE`), and reports them as
|
||||
skipped otherwise.
|
||||
|
||||
All passphrases, seeds and plaintexts in the vectors are synthetic and
|
||||
public (`oracle-real passphrase`, `oracle-decoy passphrase`, fixed byte
|
||||
patterns). Never commit real keys or real vault contents.
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regenerate the Go-oracle vectors and fixtures in tests/vectors.
|
||||
#
|
||||
# Everything is computed by the frozen Go implementation in oracle/go (see
|
||||
# oracle/README.md); nothing comes from the Rust code under test. Key files
|
||||
# and ciphertexts use fresh randomness, so regenerating changes them; the
|
||||
# deterministic vectors (*.json fields derived from fixed seeds) do not.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
out=$PWD/tests/vectors
|
||||
mkdir -p "$out"
|
||||
(cd oracle/go && VAULT_ORACLE_OUT=$out go test -count=1 -run '^TestOracleVectors$' ./ ./internal/pqcrypt ./internal/stream)
|
||||
echo "vectors written to $out"
|
||||
@@ -0,0 +1,298 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// Test-only vector generator for the Rust port. It adds nothing to the
|
||||
// production code: it only calls the frozen implementation and records what
|
||||
// it computes. Run through oracle/gen-vectors.sh.
|
||||
|
||||
package pqcrypt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/andydixon/vault/internal/format"
|
||||
"github.com/cloudflare/circl/kem"
|
||||
"github.com/cloudflare/circl/kem/frodo/frodo640shake"
|
||||
"github.com/cloudflare/circl/kem/mlkem/mlkem768"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
)
|
||||
|
||||
type kemVector struct {
|
||||
Seed string `json:"seed"`
|
||||
PubSHA256 string `json:"pub_sha256"`
|
||||
PrivSHA256 string `json:"priv_sha256"`
|
||||
EncapSeed string `json:"encap_seed"`
|
||||
CtSHA256 string `json:"ct_sha256"`
|
||||
SharedSecret string `json:"ss"`
|
||||
RejectFlipIdx int `json:"reject_flip_index"`
|
||||
RejectSS string `json:"reject_ss"`
|
||||
}
|
||||
|
||||
type hybridVector struct {
|
||||
MasterSeed string `json:"master_seed"`
|
||||
FrodoSeed string `json:"frodo_seed"`
|
||||
MLKEMSeed string `json:"mlkem_seed"`
|
||||
PubSHA256 string `json:"pub_sha256"`
|
||||
PrivSHA256 string `json:"priv_sha256"`
|
||||
PubPrefix string `json:"pub_prefix"`
|
||||
}
|
||||
|
||||
type wrapVector struct {
|
||||
MasterSeed string `json:"master_seed"`
|
||||
FrodoEncap string `json:"frodo_encap_seed"`
|
||||
MLKEMEncap string `json:"mlkem_encap_seed"`
|
||||
FileKey string `json:"file_key"`
|
||||
KEK string `json:"kek"`
|
||||
Header string `json:"header_hex"` // full serialised header, MAC line included
|
||||
MAC string `json:"mac"`
|
||||
Nonce string `json:"nonce"`
|
||||
PayloadKey string `json:"payload_key"`
|
||||
StanzaArg0 string `json:"stanza_arg0_sha256"`
|
||||
StanzaBody string `json:"stanza_body"`
|
||||
}
|
||||
|
||||
type headerCase struct {
|
||||
Input string `json:"input_hex"`
|
||||
Accept bool `json:"accept"`
|
||||
Rest string `json:"rest_hex,omitempty"` // payload bytes after the header
|
||||
}
|
||||
|
||||
func sum(b []byte) string { s := sha256.Sum256(b); return hex.EncodeToString(s[:]) }
|
||||
|
||||
func pattern(n int, salt byte) []byte {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = byte(i*7) ^ salt
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func kemVectors(t *testing.T, s kem.Scheme, n int) []kemVector {
|
||||
var out []kemVector
|
||||
for i := range n {
|
||||
seed := pattern(s.SeedSize(), byte(i*31))
|
||||
pk, sk := s.DeriveKeyPair(seed)
|
||||
pkb, _ := pk.MarshalBinary()
|
||||
skb, _ := sk.MarshalBinary()
|
||||
es := pattern(s.EncapsulationSeedSize(), byte(i*17+5))
|
||||
ct, ss, err := s.EncapsulateDeterministically(pk, es)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ss2, err := s.Decapsulate(sk, ct)
|
||||
if err != nil || !bytes.Equal(ss, ss2) {
|
||||
t.Fatal("decapsulation mismatch")
|
||||
}
|
||||
flip := (i * 997) % len(ct)
|
||||
bad := append([]byte(nil), ct...)
|
||||
bad[flip] ^= 0x01
|
||||
rss, err := s.Decapsulate(sk, bad)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out = append(out, kemVector{
|
||||
Seed: hex.EncodeToString(seed), PubSHA256: sum(pkb), PrivSHA256: sum(skb),
|
||||
EncapSeed: hex.EncodeToString(es), CtSHA256: sum(ct), SharedSecret: hex.EncodeToString(ss),
|
||||
RejectFlipIdx: flip, RejectSS: hex.EncodeToString(rss),
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestOracleVectors(t *testing.T) {
|
||||
dir := os.Getenv("VAULT_ORACLE_OUT")
|
||||
if dir == "" {
|
||||
t.Skip("set VAULT_ORACLE_OUT to write vectors")
|
||||
}
|
||||
suite := frodoMLKEM768{}
|
||||
frodo, ml := frodo640shake.Scheme(), mlkem768.Scheme()
|
||||
|
||||
var hybrids []hybridVector
|
||||
for i := range 6 {
|
||||
master := pattern(32, byte(i*53+1))
|
||||
if i == 5 {
|
||||
master = bytes.Repeat([]byte{0xff}, 32)
|
||||
}
|
||||
r := hkdf.New(sha256.New, master, nil, []byte("fury/v1 seed-expand "+suite.tag()))
|
||||
fs := make([]byte, frodo.SeedSize())
|
||||
ms := make([]byte, ml.SeedSize())
|
||||
io.ReadFull(r, fs)
|
||||
io.ReadFull(r, ms)
|
||||
pub, priv, err := suite.deriveKeypair(master)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hybrids = append(hybrids, hybridVector{
|
||||
MasterSeed: hex.EncodeToString(master), FrodoSeed: hex.EncodeToString(fs), MLKEMSeed: hex.EncodeToString(ms),
|
||||
PubSHA256: sum(pub), PrivSHA256: sum(priv), PubPrefix: hex.EncodeToString(pub[:64]),
|
||||
})
|
||||
}
|
||||
|
||||
// A wrap with controlled encapsulation randomness, built from the real
|
||||
// deriveKEK, aeadEncrypt, header marshalling, headerMAC and streamKey.
|
||||
var wraps []wrapVector
|
||||
for i := range 3 {
|
||||
master := pattern(32, byte(i*53+1))
|
||||
id, err := NewPQIdentityFromSeed(suite.id(), master)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pub := id.Recipient().Bytes()
|
||||
fpk, _ := frodo.UnmarshalBinaryPublicKey(pub[:frodo.PublicKeySize()])
|
||||
mpk, _ := ml.UnmarshalBinaryPublicKey(pub[frodo.PublicKeySize():])
|
||||
fe, me := pattern(16, byte(i+100)), pattern(32, byte(i+150))
|
||||
ct1, ss1, _ := frodo.EncapsulateDeterministically(fpk, fe)
|
||||
ct2, ss2, _ := ml.EncapsulateDeterministically(mpk, me)
|
||||
kek := suite.deriveKEK(ss1, ss2, ct1, ct2)
|
||||
fileKey := pattern(32, byte(i+200))
|
||||
body, _ := aeadEncrypt(kek, fileKey)
|
||||
st := &format.Stanza{Type: suite.tag(), Args: []string{format.EncodeToString(ct1), format.EncodeToString(ct2)}, Body: body}
|
||||
hdr := &format.Header{Recipients: []*format.Stanza{st}}
|
||||
mac, err := headerMAC(fileKey, hdr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hdr.MAC = mac
|
||||
var hb bytes.Buffer
|
||||
hdr.Marshal(&hb)
|
||||
// The real identity must open what was built.
|
||||
got, err := id.Unwrap([]*Stanza{(*Stanza)(st)})
|
||||
if err != nil || !bytes.Equal(got, fileKey) {
|
||||
t.Fatal("identity did not unwrap the vector")
|
||||
}
|
||||
nonce := pattern(16, byte(i+250))
|
||||
wraps = append(wraps, wrapVector{
|
||||
MasterSeed: hex.EncodeToString(master), FrodoEncap: hex.EncodeToString(fe), MLKEMEncap: hex.EncodeToString(me),
|
||||
FileKey: hex.EncodeToString(fileKey), KEK: hex.EncodeToString(kek), Header: hex.EncodeToString(hb.Bytes()),
|
||||
MAC: hex.EncodeToString(mac), Nonce: hex.EncodeToString(nonce), PayloadKey: hex.EncodeToString(streamKey(fileKey, nonce)),
|
||||
StanzaArg0: sum([]byte(st.Args[0])), StanzaBody: hex.EncodeToString(body),
|
||||
})
|
||||
}
|
||||
|
||||
// Whole files from the real Encrypt, with fresh randomness, for the
|
||||
// first hybrid identity. Plaintexts are pattern(size, 0x5a).
|
||||
id, _ := NewPQIdentityFromSeed(suite.id(), pattern(32, 1))
|
||||
fdir := filepath.Join(dir, "fury")
|
||||
os.MkdirAll(fdir, 0o755)
|
||||
for _, size := range []int{0, 1, 65535, 65536, 65537, 131072, 200000} {
|
||||
var buf bytes.Buffer
|
||||
w, err := Encrypt(&buf, id.Recipient())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w.Write(pattern(size, 0x5a))
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.WriteFile(filepath.Join(fdir, "pattern-"+itoa(size)+".fury"), buf.Bytes(), 0o644)
|
||||
}
|
||||
|
||||
// Header parser verdicts on valid and malformed headers.
|
||||
var cases []headerCase
|
||||
valid, _ := hex.DecodeString(wraps[0].Header)
|
||||
add := func(b []byte) {
|
||||
h, payload, err := format.Parse(bytes.NewReader(b))
|
||||
c := headerCase{Input: hex.EncodeToString(b), Accept: err == nil}
|
||||
if err == nil {
|
||||
rest, _ := io.ReadAll(payload)
|
||||
c.Rest = hex.EncodeToString(rest)
|
||||
var again bytes.Buffer
|
||||
h.Marshal(&again)
|
||||
}
|
||||
cases = append(cases, c)
|
||||
}
|
||||
for _, m := range headerMutations(valid) {
|
||||
add(m)
|
||||
}
|
||||
|
||||
write(t, filepath.Join(dir, "crypto.json"), map[string]any{
|
||||
"provenance": "oracle/go at 4c1507c, internal/pqcrypt/oracle_vectors_test.go",
|
||||
"frodo640shake": kemVectors(t, frodo, 8),
|
||||
"mlkem768": kemVectors(t, ml, 8),
|
||||
"hybrid": hybrids,
|
||||
"wrap": wraps,
|
||||
"header_cases": cases,
|
||||
})
|
||||
}
|
||||
|
||||
func itoa(n int) string { return string(appendInt(nil, n)) }
|
||||
|
||||
func appendInt(b []byte, n int) []byte {
|
||||
if n >= 10 {
|
||||
b = appendInt(b, n/10)
|
||||
}
|
||||
return append(b, byte('0'+n%10))
|
||||
}
|
||||
|
||||
// headerMutations returns valid headers plus a range of malformed ones.
|
||||
func headerMutations(valid []byte) [][]byte {
|
||||
s := string(valid)
|
||||
introEnd := bytes.IndexByte(valid, '\n') + 1
|
||||
footer := bytes.LastIndex(valid, []byte("\n---")) + 1
|
||||
lines := bytes.SplitAfter(valid, []byte("\n"))
|
||||
join := func(ls [][]byte) []byte { return bytes.Join(ls, nil) }
|
||||
var out [][]byte
|
||||
push := func(b []byte) { out = append(out, append([]byte(nil), b...)) }
|
||||
push(valid)
|
||||
push(append(append([]byte(nil), valid...), []byte("payload\x00\x01")...))
|
||||
push([]byte(""))
|
||||
push([]byte("fury-encryption.org/v1\n--- " + s[len(s)-44:])) // no stanzas
|
||||
push([]byte("fury-encryption.org/v2\n" + s[introEnd:])) // wrong intro
|
||||
push([]byte("fury-encryption.org/v1" + s[introEnd:])) // intro without newline
|
||||
push(valid[:footer]) // no footer
|
||||
push(valid[:len(valid)-1]) // footer without newline
|
||||
push(append(append([]byte(nil), valid[:len(valid)-1]...), '=', '\n')) // padded MAC
|
||||
push([]byte(s[:footer] + "--- " + s[footer+4:])) // double space
|
||||
push([]byte(s[:footer] + "---x " + s[footer+4:])) // bad footer prefix
|
||||
push([]byte(s[:footer] + "--- " + s[footer+4:len(s)-2] + "\n")) // short MAC
|
||||
push([]byte(s[:footer] + "--- " + s[footer+4:len(s)-1] + " x\n"))
|
||||
// Stanza line edits.
|
||||
stanza := lines[1]
|
||||
for _, edit := range []string{"-> \n", "->\n", "-> x\n", "-> x\x7f\n", "-> x é\n", "-x a\n", "-> x y\n", "-> x\r\n"} {
|
||||
ls := append([][]byte(nil), lines...)
|
||||
ls[1] = []byte(edit)
|
||||
push(join(ls))
|
||||
_ = stanza
|
||||
}
|
||||
// Body edits: the body is the two lines after the stanza line.
|
||||
body := 2
|
||||
for _, edit := range []string{"\n", "AAAA\n", "AAAA=\n", "A\n", "AB\n", "AAB\n", "AA==\n", " AAAA\n", "AAAA\r\n",
|
||||
string(bytes.Repeat([]byte("A"), 64)) + "\n", string(bytes.Repeat([]byte("A"), 68)) + "\n", string(bytes.Repeat([]byte("A"), 65)) + "\n"} {
|
||||
ls := append([][]byte(nil), lines...)
|
||||
ls[body] = []byte(edit)
|
||||
push(join(ls))
|
||||
}
|
||||
{
|
||||
// Drop the empty line that ends a 48-byte body: the stanza then runs
|
||||
// into the footer.
|
||||
ls := append([][]byte(nil), lines...)
|
||||
ls = append(ls[:3], ls[4:]...)
|
||||
push(join(ls))
|
||||
}
|
||||
{
|
||||
// A second, foreign stanza ahead of the real one.
|
||||
ls := append([][]byte(nil), lines[:1]...)
|
||||
ls = append(ls, []byte("-> other-suite arg\n"), []byte("AAAA\n"))
|
||||
ls = append(ls, lines[1:]...)
|
||||
push(join(ls))
|
||||
}
|
||||
// The 1 MiB stanza and 16 MiB header limits are exercised by the Rust
|
||||
// tests directly; vectors that size would bloat the repository.
|
||||
return out
|
||||
}
|
||||
|
||||
func write(t *testing.T, path string, v any) {
|
||||
b, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(path, append(b, '\n'), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// Test-only vector generator for the Rust port; see oracle/gen-vectors.sh.
|
||||
|
||||
package stream
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOracleVectors(t *testing.T) {
|
||||
dir := os.Getenv("VAULT_ORACLE_OUT")
|
||||
if dir == "" {
|
||||
t.Skip("set VAULT_ORACLE_OUT to write vectors")
|
||||
}
|
||||
key := make([]byte, 32)
|
||||
for i := range key {
|
||||
key[i] = byte(i + 1)
|
||||
}
|
||||
type vec struct {
|
||||
Size int `json:"size"`
|
||||
CtLen int `json:"ct_len"`
|
||||
CtSHA256 string `json:"ct_sha256"`
|
||||
CtHex string `json:"ct_hex,omitempty"`
|
||||
}
|
||||
var vs []vec
|
||||
for _, size := range []int{0, 1, 15, 16, 17, ChunkSize - 1, ChunkSize, ChunkSize + 1, 2 * ChunkSize, 2*ChunkSize + 1, 3*ChunkSize - 16, 300000} {
|
||||
pt := make([]byte, size)
|
||||
for i := range pt {
|
||||
pt[i] = byte(i*13 + 7)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
w, _ := NewEncryptWriter(key, &buf)
|
||||
w.Write(pt)
|
||||
w.Close()
|
||||
// The reader-side encryptor must agree.
|
||||
r, _ := NewEncryptReader(key, bytes.NewReader(pt))
|
||||
alt, _ := io.ReadAll(r)
|
||||
if !bytes.Equal(alt, buf.Bytes()) {
|
||||
t.Fatal("EncryptReader disagrees with EncryptWriter")
|
||||
}
|
||||
s := sha256.Sum256(buf.Bytes())
|
||||
v := vec{Size: size, CtLen: buf.Len(), CtSHA256: hex.EncodeToString(s[:])}
|
||||
if size <= 17 {
|
||||
v.CtHex = hex.EncodeToString(buf.Bytes())
|
||||
}
|
||||
vs = append(vs, v)
|
||||
}
|
||||
b, _ := json.MarshalIndent(map[string]any{
|
||||
"provenance": "oracle/go at 4c1507c, internal/stream/oracle_vectors_test.go",
|
||||
"key": hex.EncodeToString(key),
|
||||
"plaintext": "byte(i*13+7)",
|
||||
"vectors": vs,
|
||||
}, "", " ")
|
||||
if err := os.WriteFile(filepath.Join(dir, "stream.json"), append(b, '\n'), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// Test-only vector and fixture generator for the Rust port. It calls the
|
||||
// frozen implementation and records what it computes; it changes nothing in
|
||||
// the vault binary. Run through oracle/gen-vectors.sh.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/andydixon/vault/internal/pqcrypt"
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
|
||||
// Synthetic, public test passphrases. Never use them for anything real.
|
||||
const (
|
||||
oracleReal = "oracle-real passphrase"
|
||||
oracleDecoy = "oracle-decoy passphrase"
|
||||
)
|
||||
|
||||
func TestOracleVectors(t *testing.T) {
|
||||
dir := os.Getenv("VAULT_ORACLE_OUT")
|
||||
if dir == "" {
|
||||
t.Skip("set VAULT_ORACLE_OUT to write vectors")
|
||||
}
|
||||
out := map[string]any{"provenance": "oracle/go at 4c1507c, oracle_vectors_test.go"}
|
||||
|
||||
// Key files.
|
||||
keys := map[string]any{}
|
||||
for _, k := range []struct{ name, real, decoy string }{
|
||||
{"key-with-decoy.pem", oracleReal, oracleDecoy},
|
||||
{"key-no-decoy.pem", oracleReal, ""},
|
||||
} {
|
||||
p := filepath.Join(dir, k.name)
|
||||
os.Remove(p)
|
||||
if err := writeKeyFile(p, k.real, k.decoy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
entry := map[string]any{}
|
||||
for label, pass := range map[string]string{"real": k.real, "decoy": k.decoy} {
|
||||
if pass == "" {
|
||||
continue
|
||||
}
|
||||
id, err := unlockKeyFile(p, pass)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
entry[label] = map[string]any{"passphrase": pass, "suite": id.SuiteID(), "seed": hex.EncodeToString(id.Seed())}
|
||||
}
|
||||
keys[k.name] = entry
|
||||
}
|
||||
out["keys"] = keys
|
||||
|
||||
var argon []map[string]string
|
||||
for i, pass := range []string{"", "a", "correct horse", "pässwörd ü", "x\x00y"} {
|
||||
salt := make([]byte, 16)
|
||||
for j := range salt {
|
||||
salt[j] = byte(i*16 + j)
|
||||
}
|
||||
k := argon2.IDKey([]byte(pass), salt, argonTime, argonMemory, argonThreads, 32)
|
||||
argon = append(argon, map[string]string{"passphrase_hex": hex.EncodeToString([]byte(pass)), "salt": hex.EncodeToString(salt), "key": hex.EncodeToString(k)})
|
||||
}
|
||||
out["argon2id"] = argon
|
||||
out["key_header_hex"] = hex.EncodeToString(keyHeader())
|
||||
|
||||
// Object IDs and sizes.
|
||||
seed := "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
|
||||
var ids []string
|
||||
for i := range int64(4) {
|
||||
ids = append(ids, objectID(seed, i))
|
||||
}
|
||||
out["object_ids"] = map[string]any{"seed": seed, "ids": ids, "big_index": objectID(seed, 1<<40), "big_index_value": int64(1 << 40)}
|
||||
padded := map[string]int64{}
|
||||
counts := map[string]int64{}
|
||||
for _, n := range []int64{0, 1, 16, 65535, 65536, 65537, 1 << 20, chunkSize - 1, chunkSize, chunkData - 1, chunkData, chunkData + 1, 2 * chunkData, fileLimit} {
|
||||
padded[fmt.Sprint(n)] = paddedSize(n)
|
||||
counts[fmt.Sprint(n)] = objectCount(n)
|
||||
}
|
||||
out["padded_size"] = padded
|
||||
out["object_count"] = counts
|
||||
|
||||
names := map[string]bool{}
|
||||
for _, n := range []string{"", "a", "a/b", "/a", "a/", "a//b", "./a", "a/./b", "../a", "a/..", "..", ".", "a/../b", "a\\b", "a\x00b",
|
||||
"a\nb", "a\x7fb", "a\u0085b", "ü/ñ", "\xff", "a b", " a", "...", "a/...", "..a", "a/.b", string(make([]byte, 1024)), longName(1024), longName(1025), "ab", "
"} {
|
||||
names[hex.EncodeToString([]byte(n))] = validName(n)
|
||||
}
|
||||
out["valid_name_hex"] = names
|
||||
|
||||
sizes := map[string]any{}
|
||||
for _, s := range []string{"0", "512", "2k", "500M", "2G", "1TB", "", "G", "-1", "2X", "1.5G", "2T", "+5", "1KB", "1MK", "1kb", "B", "1T", "1099511627776", "1099511627777", " 1", "0x10", "1024G", "1025G", "-0", "1bb"} {
|
||||
n, err := parseSize(s)
|
||||
if err != nil {
|
||||
sizes[s] = nil
|
||||
} else {
|
||||
sizes[s] = n
|
||||
}
|
||||
}
|
||||
out["parse_size"] = sizes
|
||||
|
||||
human := map[string]string{}
|
||||
for _, n := range []int64{0, 1, 1023, 1024, 1025, 1536, 1101, 10239, 10240, 1048575, 1048576, 1 << 30, 1<<40 - 1, 1 << 40, 1<<62 + 12345, 1<<63 - 1, 1075, 1126, 1177, 1638, 1689} {
|
||||
human[fmt.Sprint(n)] = humanSize(n)
|
||||
}
|
||||
out["human_size"] = human
|
||||
|
||||
clean := map[string]string{}
|
||||
for _, p := range []string{"", ".", "..", "/", "//", "a/b/../c", "/../a", "a/./b/", "../../a", "a//b", "./", "/a/b/..", "a/b/../../..", "abc/def/ghi/../.."} {
|
||||
clean[p] = path.Clean(p)
|
||||
}
|
||||
out["path_clean"] = clean
|
||||
|
||||
durs := map[string]any{}
|
||||
for _, d := range []string{"5m", "1h", "90s", "1.5h", "300ms", "1h30m", "0", "-5m", "", "5", "1d", "2h45m30.5s", "1us", "1µs", "1ns", ".5s", "5.s", "+5m", "9223372036854775807ns", "9223372036854775808ns"} {
|
||||
v, err := time.ParseDuration(d)
|
||||
if err != nil {
|
||||
durs[d] = nil
|
||||
} else {
|
||||
durs[d] = map[string]any{"ns": int64(v), "string": v.String()}
|
||||
}
|
||||
}
|
||||
out["durations"] = durs
|
||||
|
||||
// Record JSON, exactly as written.
|
||||
var recs []map[string]any
|
||||
for _, r := range []record{
|
||||
{Name: "plain.txt", Seed: seed, Size: 5, Mode: 0o644, Modified: time.Unix(1700000000, 123456789).UTC(), Added: time.Unix(1700000001, 0).UTC()},
|
||||
{Name: "<a&b>/
'\"\\x", Seed: seed, Size: 0, Mode: 0o755, Modified: time.Unix(0, 0).UTC(), Added: time.Unix(1, 100).UTC()},
|
||||
{Name: "ü/日本語", Seed: seed, Size: 1 << 40, Mode: 0o600, Modified: time.Unix(-1, 500000000).UTC(), Added: time.Unix(253402300799, 999999999).UTC()},
|
||||
{Name: "tab\there", Seed: seed, Size: 1, Mode: 0, Modified: time.Unix(1234567890, 120000000).UTC(), Added: time.Unix(1234567890, 1000).UTC()},
|
||||
} {
|
||||
b, err := json.Marshal(&r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
recs = append(recs, map[string]any{"json": string(b), "name": r.Name, "modified_unix_nano": r.Modified.UnixNano(), "added_unix_nano": r.Added.UnixNano()})
|
||||
}
|
||||
out["records"] = recs
|
||||
|
||||
writeMiniVault(t, filepath.Join(dir, "mini-vault"), filepath.Join(dir, "key-with-decoy.pem"))
|
||||
|
||||
b, _ := json.MarshalIndent(out, "", " ")
|
||||
if err := os.WriteFile(filepath.Join(dir, "store.json"), append(b, '\n'), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func longName(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = 'a' + byte(i%26)
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// writeMiniVault builds a small vault through the real store code, without
|
||||
// init's filler (which would make the fixture megabytes): three real files,
|
||||
// one decoy file and one record sealed to a throwaway key.
|
||||
func writeMiniVault(t *testing.T, root, keyPath string) {
|
||||
os.RemoveAll(root)
|
||||
for _, d := range []string{recordsDir, objectsDir} {
|
||||
for i := range 256 {
|
||||
if err := os.MkdirAll(filepath.Join(root, d, fmt.Sprintf("%02x", i)), 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
os.WriteFile(filepath.Join(root, markerName), []byte(markerContent), 0o600)
|
||||
src := filepath.Join(t.TempDir(), "src")
|
||||
put := func(s *store, name string, body []byte, mode os.FileMode, mtime time.Time) {
|
||||
os.WriteFile(src, body, 0o600)
|
||||
os.Chmod(src, mode)
|
||||
os.Chtimes(src, mtime, mtime)
|
||||
cat, err := s.catalogue()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := s.add(cat, src, name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
real, _ := unlockKeyFile(keyPath, oracleReal)
|
||||
decoy, _ := unlockKeyFile(keyPath, oracleDecoy)
|
||||
throwaway, _ := pqcrypt.GeneratePQIdentity()
|
||||
rs := &store{root: root, id: real}
|
||||
boundary := make([]byte, minPadding-idSize)
|
||||
for i := range boundary {
|
||||
boundary[i] = byte(i * 7)
|
||||
}
|
||||
put(rs, "hello.txt", []byte("hello"), 0o644, time.Unix(1700000000, 123456789))
|
||||
put(rs, "dir/empty", nil, 0o600, time.Unix(1600000000, 0))
|
||||
put(rs, "dir/ünïcode.bin", boundary, 0o755, time.Unix(1500000000, 999999999))
|
||||
put(&store{root: root, id: decoy}, "shopping.txt", []byte("milk\n"), 0o600, time.Unix(1700000000, 0))
|
||||
put(&store{root: root, id: throwaway}, "foreign", []byte("not yours"), 0o600, time.Unix(1700000000, 0))
|
||||
for _, d := range []string{recordsDir, objectsDir} {
|
||||
shards, _ := filepath.Glob(filepath.Join(root, d, "??"))
|
||||
for _, p := range append(shards, filepath.Join(root, d)) {
|
||||
os.Chtimes(p, epoch, epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
-----BEGIN VAULT KEY-----
|
||||
VkFVTFRLRVkxAAAAAwABAAAE7NkqKMY7sbZZjHitika7SuJ2Nn8IXjsNrc05bRD3
|
||||
/5n6gg09m6shM9w4JZCrZ84P9QdttuuLaTotx4TIi6ALwRpuQ1GETVN8aC2cPUlQ
|
||||
eAZjKThQyzilIkqfNWBEk6O1SWHiH4RM7wvmXM2HraTzWiKrLC0hc8Fhcdwv/eDR
|
||||
kM6uh6iAmk74hWC8PIWuSscS5aW7Vl2OAyKr7vISRH611vXXsSwAAcEAPcoMeKgD
|
||||
YQcl9EJX
|
||||
-----END VAULT KEY-----
|
||||
@@ -0,0 +1,7 @@
|
||||
-----BEGIN VAULT KEY-----
|
||||
VkFVTFRLRVkxAAAAAwABAAAEgOQrPuXO8L/uhqn/gPncOQDW1UGohTv1BUEG37eX
|
||||
g/wZRVl2Nptu6xbqAhL1xgLstttod4sT5iNfFxvYsZnSQLsCMjaNwO5/a8rn8fOw
|
||||
QhRKx38573ADf3kA8Hv9qiykMgEAa3Ml9Qz6vlqB5gRWuK4meXSpEuxdz7XcpxIn
|
||||
lOo0jYKzagOhNM40jTBkiQmJvvYJIWt48Ckl/goDk+GQRY1SWFRW0ioQF89dHK7D
|
||||
XlBfBz9o
|
||||
-----END VAULT KEY-----
|
||||
@@ -0,0 +1 @@
|
||||
VAULT 2
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,291 @@
|
||||
{
|
||||
"argon2id": [
|
||||
{
|
||||
"key": "ad4a178e6b0786a48f9bb3443df83f76b822c6fdac15a80277483fd84551ac52",
|
||||
"passphrase_hex": "",
|
||||
"salt": "000102030405060708090a0b0c0d0e0f"
|
||||
},
|
||||
{
|
||||
"key": "31d553d292080fe042ee1a2d65b3673aedaa45cc63611410a866805455452d2c",
|
||||
"passphrase_hex": "61",
|
||||
"salt": "101112131415161718191a1b1c1d1e1f"
|
||||
},
|
||||
{
|
||||
"key": "537025a925815556ec88beffea074f810f5a28b6c5f5ccea0077f2819e8b3fb8",
|
||||
"passphrase_hex": "636f727265637420686f727365",
|
||||
"salt": "202122232425262728292a2b2c2d2e2f"
|
||||
},
|
||||
{
|
||||
"key": "24d4e3608a444089a6f78ef8b07946879e570652b8387414895e0ad55ae68fb2",
|
||||
"passphrase_hex": "70c3a4737377c3b6726420c3bc",
|
||||
"salt": "303132333435363738393a3b3c3d3e3f"
|
||||
},
|
||||
{
|
||||
"key": "bccc0063f95f2003f01532a75ae0feff25bdce4d940b904753d3b0326563a944",
|
||||
"passphrase_hex": "780079",
|
||||
"salt": "404142434445464748494a4b4c4d4e4f"
|
||||
}
|
||||
],
|
||||
"durations": {
|
||||
"": null,
|
||||
"+5m": {
|
||||
"ns": 300000000000,
|
||||
"string": "5m0s"
|
||||
},
|
||||
"-5m": {
|
||||
"ns": -300000000000,
|
||||
"string": "-5m0s"
|
||||
},
|
||||
".5s": {
|
||||
"ns": 500000000,
|
||||
"string": "500ms"
|
||||
},
|
||||
"0": {
|
||||
"ns": 0,
|
||||
"string": "0s"
|
||||
},
|
||||
"1.5h": {
|
||||
"ns": 5400000000000,
|
||||
"string": "1h30m0s"
|
||||
},
|
||||
"1d": null,
|
||||
"1h": {
|
||||
"ns": 3600000000000,
|
||||
"string": "1h0m0s"
|
||||
},
|
||||
"1h30m": {
|
||||
"ns": 5400000000000,
|
||||
"string": "1h30m0s"
|
||||
},
|
||||
"1ns": {
|
||||
"ns": 1,
|
||||
"string": "1ns"
|
||||
},
|
||||
"1us": {
|
||||
"ns": 1000,
|
||||
"string": "1µs"
|
||||
},
|
||||
"1µs": {
|
||||
"ns": 1000,
|
||||
"string": "1µs"
|
||||
},
|
||||
"2h45m30.5s": {
|
||||
"ns": 9930500000000,
|
||||
"string": "2h45m30.5s"
|
||||
},
|
||||
"300ms": {
|
||||
"ns": 300000000,
|
||||
"string": "300ms"
|
||||
},
|
||||
"5": null,
|
||||
"5.s": {
|
||||
"ns": 5000000000,
|
||||
"string": "5s"
|
||||
},
|
||||
"5m": {
|
||||
"ns": 300000000000,
|
||||
"string": "5m0s"
|
||||
},
|
||||
"90s": {
|
||||
"ns": 90000000000,
|
||||
"string": "1m30s"
|
||||
},
|
||||
"9223372036854775807ns": {
|
||||
"ns": 9223372036854775807,
|
||||
"string": "2562047h47m16.854775807s"
|
||||
},
|
||||
"9223372036854775808ns": null
|
||||
},
|
||||
"human_size": {
|
||||
"0": "0 B",
|
||||
"1": "1 B",
|
||||
"1023": "1023 B",
|
||||
"10239": "10.0 KiB",
|
||||
"1024": "1.0 KiB",
|
||||
"10240": "10.0 KiB",
|
||||
"1025": "1.0 KiB",
|
||||
"1048575": "1024.0 KiB",
|
||||
"1048576": "1.0 MiB",
|
||||
"1073741824": "1.0 GiB",
|
||||
"1075": "1.0 KiB",
|
||||
"1099511627775": "1024.0 GiB",
|
||||
"1099511627776": "1.0 TiB",
|
||||
"1101": "1.1 KiB",
|
||||
"1126": "1.1 KiB",
|
||||
"1177": "1.1 KiB",
|
||||
"1536": "1.5 KiB",
|
||||
"1638": "1.6 KiB",
|
||||
"1689": "1.6 KiB",
|
||||
"4611686018427400249": "4.0 EiB",
|
||||
"9223372036854775807": "8.0 EiB"
|
||||
},
|
||||
"key_header_hex": "5641554c544b455931000000030001000004",
|
||||
"keys": {
|
||||
"key-no-decoy.pem": {
|
||||
"real": {
|
||||
"passphrase": "oracle-real passphrase",
|
||||
"seed": "6ba0719d2a5433702aa5cc4948ef81f0dfc74ca1a3d1bb0a7ebcf08b283c17d4",
|
||||
"suite": 1
|
||||
}
|
||||
},
|
||||
"key-with-decoy.pem": {
|
||||
"decoy": {
|
||||
"passphrase": "oracle-decoy passphrase",
|
||||
"seed": "8123774aca365941cfbb50482315c8bdba09744d24b5f3ae9a6597578b246259",
|
||||
"suite": 1
|
||||
},
|
||||
"real": {
|
||||
"passphrase": "oracle-real passphrase",
|
||||
"seed": "d11a7d21d5eb484aff4fbbfb4dd05469e719ca0338d8475bd0547fe7e42e706c",
|
||||
"suite": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"object_count": {
|
||||
"0": 1,
|
||||
"1": 1,
|
||||
"1048576": 1,
|
||||
"1099511627776": 262146,
|
||||
"16": 1,
|
||||
"4194287": 1,
|
||||
"4194288": 1,
|
||||
"4194289": 2,
|
||||
"4194303": 2,
|
||||
"4194304": 2,
|
||||
"65535": 1,
|
||||
"65536": 1,
|
||||
"65537": 1,
|
||||
"8388576": 2
|
||||
},
|
||||
"object_ids": {
|
||||
"big_index": "0f793077e14e9c9c44cffd32229248aa",
|
||||
"big_index_value": 1099511627776,
|
||||
"ids": [
|
||||
"9f0cd9b94097fe4929918d2b8942b344",
|
||||
"c432e059c378eef7fe2f1181a4050836",
|
||||
"f92ad613cd014c7449fcc5d4ce98ad02",
|
||||
"96cee9f29e43c395c608a454b854da2b"
|
||||
],
|
||||
"seed": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
|
||||
},
|
||||
"padded_size": {
|
||||
"0": 65536,
|
||||
"1": 65536,
|
||||
"1048576": 1048576,
|
||||
"1099511627776": 1099511627776,
|
||||
"16": 65536,
|
||||
"4194287": 4194304,
|
||||
"4194288": 4194304,
|
||||
"4194289": 4194304,
|
||||
"4194303": 4194304,
|
||||
"4194304": 4194304,
|
||||
"65535": 65536,
|
||||
"65536": 65536,
|
||||
"65537": 131072,
|
||||
"8388576": 8388608
|
||||
},
|
||||
"parse_size": {
|
||||
"": null,
|
||||
" 1": null,
|
||||
"+5": 5,
|
||||
"-0": 0,
|
||||
"-1": null,
|
||||
"0": 0,
|
||||
"0x10": null,
|
||||
"1.5G": null,
|
||||
"1024G": 1099511627776,
|
||||
"1025G": null,
|
||||
"1099511627776": 1099511627776,
|
||||
"1099511627777": null,
|
||||
"1KB": 1024,
|
||||
"1MK": 1048576,
|
||||
"1T": 1099511627776,
|
||||
"1TB": 1099511627776,
|
||||
"1bb": null,
|
||||
"1kb": 1024,
|
||||
"2G": 2147483648,
|
||||
"2T": null,
|
||||
"2X": null,
|
||||
"2k": 2048,
|
||||
"500M": 524288000,
|
||||
"512": 512,
|
||||
"B": null,
|
||||
"G": null
|
||||
},
|
||||
"path_clean": {
|
||||
"": ".",
|
||||
".": ".",
|
||||
"..": "..",
|
||||
"../../a": "../../a",
|
||||
"./": ".",
|
||||
"/": "/",
|
||||
"/../a": "/a",
|
||||
"//": "/",
|
||||
"/a/b/..": "/a",
|
||||
"a/./b/": "a/b",
|
||||
"a//b": "a/b",
|
||||
"a/b/../../..": "..",
|
||||
"a/b/../c": "a/c",
|
||||
"abc/def/ghi/../..": "abc"
|
||||
},
|
||||
"provenance": "oracle/go at 4c1507c, oracle_vectors_test.go",
|
||||
"records": [
|
||||
{
|
||||
"added_unix_nano": 1700000001000000000,
|
||||
"json": "{\"name\":\"plain.txt\",\"seed\":\"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\",\"size\":5,\"mode\":420,\"modified\":\"2023-11-14T22:13:20.123456789Z\",\"added\":\"2023-11-14T22:13:21Z\"}",
|
||||
"modified_unix_nano": 1700000000123456789,
|
||||
"name": "plain.txt"
|
||||
},
|
||||
{
|
||||
"added_unix_nano": 1000000100,
|
||||
"json": "{\"name\":\"\\u003ca\\u0026b\\u003e/\\u2028\\u2029'\\\"\\\\x\",\"seed\":\"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\",\"size\":0,\"mode\":493,\"modified\":\"1970-01-01T00:00:00Z\",\"added\":\"1970-01-01T00:00:01.0000001Z\"}",
|
||||
"modified_unix_nano": 0,
|
||||
"name": "\u003ca\u0026b\u003e/\u2028\u2029'\"\\x"
|
||||
},
|
||||
{
|
||||
"added_unix_nano": -4852116231933722625,
|
||||
"json": "{\"name\":\"ü/日本語\",\"seed\":\"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\",\"size\":1099511627776,\"mode\":384,\"modified\":\"1969-12-31T23:59:59.5Z\",\"added\":\"9999-12-31T23:59:59.999999999Z\"}",
|
||||
"modified_unix_nano": -500000000,
|
||||
"name": "ü/日本語"
|
||||
},
|
||||
{
|
||||
"added_unix_nano": 1234567890000001000,
|
||||
"json": "{\"name\":\"tab\\there\",\"seed\":\"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\",\"size\":1,\"mode\":0,\"modified\":\"2009-02-13T23:31:30.12Z\",\"added\":\"2009-02-13T23:31:30.000001Z\"}",
|
||||
"modified_unix_nano": 1234567890120000000,
|
||||
"name": "tab\there"
|
||||
}
|
||||
],
|
||||
"valid_name_hex": {
|
||||
"": false,
|
||||
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000": false,
|
||||
"2061": true,
|
||||
"2e": false,
|
||||
"2e2e": false,
|
||||
"2e2e2e": true,
|
||||
"2e2e2f61": false,
|
||||
"2e2e61": true,
|
||||
"2e2f61": false,
|
||||
"2f61": false,
|
||||
"61": true,
|
||||
"610062": false,
|
||||
"610a62": false,
|
||||
"612062": true,
|
||||
"612f": false,
|
||||
"612f2e2e": false,
|
||||
"612f2e2e2e": true,
|
||||
"612f2e2e2f62": false,
|
||||
"612f2e2f62": false,
|
||||
"612f2e62": true,
|
||||
"612f2f62": false,
|
||||
"612f62": true,
|
||||
"615c62": false,
|
||||
"6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a": true,
|
||||
"6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b6c6d6e6f707172737475767778797a6162636465666768696a6b": false,
|
||||
"617f62": false,
|
||||
"61c28562": false,
|
||||
"61e2808b62": true,
|
||||
"c3bc2fc3b1": true,
|
||||
"e280a8": true,
|
||||
"ff": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"key": "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20",
|
||||
"plaintext": "byte(i*13+7)",
|
||||
"provenance": "oracle/go at 4c1507c, internal/stream/oracle_vectors_test.go",
|
||||
"vectors": [
|
||||
{
|
||||
"size": 0,
|
||||
"ct_len": 16,
|
||||
"ct_sha256": "b5e6c4d4c2d8e2448c7b13550cb447361c6319f8303eb2189e3c00109946633e",
|
||||
"ct_hex": "ebc87bb498d2cf767b620485d8e74873"
|
||||
},
|
||||
{
|
||||
"size": 1,
|
||||
"ct_len": 17,
|
||||
"ct_sha256": "4b431b2d3c656dd5565f045f3afaa216a29bd624d84b14a6b15ad7fcdf0bcc3c",
|
||||
"ct_hex": "13e2ae1e27b20a055d353c18584d29dfec"
|
||||
},
|
||||
{
|
||||
"size": 15,
|
||||
"ct_len": 31,
|
||||
"ct_sha256": "a226ce0a65bacca756d4620c4a8103df0009486b7db9a36c577ac305c03f23bb",
|
||||
"ct_hex": "13485b85b3b4d036ed77edd5eb120ae816391a9b23c88452779018a527ffd0"
|
||||
},
|
||||
{
|
||||
"size": 16,
|
||||
"ct_len": 32,
|
||||
"ct_sha256": "fa29f52ecc1bce80108d7fc89f1d55ec231ab3eb9308d0ded0bb525e3ec6addd",
|
||||
"ct_hex": "13485b85b3b4d036ed77edd5eb120afe1d7171433f4aa6d81d9f1a1c43f1563f"
|
||||
},
|
||||
{
|
||||
"size": 17,
|
||||
"ct_len": 33,
|
||||
"ct_sha256": "e7519a9721bc45677ae60f546e6b1909ad89b6bd9041388f5b501efbbfd956de",
|
||||
"ct_hex": "13485b85b3b4d036ed77edd5eb120afe778bfe094bac290062ec1b004fabc63ceb"
|
||||
},
|
||||
{
|
||||
"size": 65535,
|
||||
"ct_len": 65551,
|
||||
"ct_sha256": "89435c31d8a1759df899f6fd7bc9a030ad0ef2d9151b746fb289fe994d9f567a"
|
||||
},
|
||||
{
|
||||
"size": 65536,
|
||||
"ct_len": 65552,
|
||||
"ct_sha256": "2b1c36c92c08df57448197d86efb6b321e29141ffb1b241eb3f90961f760a9b6"
|
||||
},
|
||||
{
|
||||
"size": 65537,
|
||||
"ct_len": 65569,
|
||||
"ct_sha256": "eb41600f5ad326e7d7056ae89e94bd29a05525e8b471c210af4a1b4275798a09"
|
||||
},
|
||||
{
|
||||
"size": 131072,
|
||||
"ct_len": 131104,
|
||||
"ct_sha256": "752ee27990e31a12fe923039a1a7fcd83f267fd3e9a237cab86f6df7575d4350"
|
||||
},
|
||||
{
|
||||
"size": 131073,
|
||||
"ct_len": 131121,
|
||||
"ct_sha256": "b93769dc38c7cebe0aa0196e2124f20eff2e50bdab01ed03313dcc29bef39c38"
|
||||
},
|
||||
{
|
||||
"size": 196592,
|
||||
"ct_len": 196640,
|
||||
"ct_sha256": "7ca38701023c57deb64762376269ea37f32b8f462fd57db22ba99b3a6a440ba3"
|
||||
},
|
||||
{
|
||||
"size": 300000,
|
||||
"ct_len": 300080,
|
||||
"ct_sha256": "ecd2f49ba7cd7d4efc39243d10e9ae4264fc4b5e182a92335587dd54822eefac"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user