1package main
2
3import (
4	"bufio"
5	"bytes"
6	"golang.org/x/crypto/cast5"
7	"crypto/cipher"
8	"encoding/hex"
9	"fmt"
10	"os"
11	"strings"
12)
13
14func unhexlify(s string) []byte {
15	bytes, err := hex.DecodeString(s)
16	if err != nil {
17		panic(err)
18	}
19	return bytes
20}
21
22type vectorArgs struct {
23	count      string
24	key        string
25	iv         string
26	plaintext  string
27	ciphertext string
28}
29
30type vectorVerifier interface {
31	validate(count string, key, iv, plaintext, expectedCiphertext []byte)
32}
33
34type ofbVerifier struct{}
35
36func (o ofbVerifier) validate(count string, key, iv, plaintext, expectedCiphertext []byte) {
37	block, err := cast5.NewCipher(key)
38	if err != nil {
39		panic(err)
40	}
41
42	ciphertext := make([]byte, len(plaintext))
43	stream := cipher.NewOFB(block, iv)
44	stream.XORKeyStream(ciphertext, plaintext)
45
46	if !bytes.Equal(ciphertext, expectedCiphertext) {
47		panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n  %s != %s\n",
48			count,
49			hex.EncodeToString(expectedCiphertext),
50			hex.EncodeToString(ciphertext)))
51	}
52}
53
54type cbcVerifier struct{}
55
56func (o cbcVerifier) validate(count string, key, iv, plaintext, expectedCiphertext []byte) {
57	block, err := cast5.NewCipher(key)
58	if err != nil {
59		panic(err)
60	}
61
62	ciphertext := make([]byte, len(plaintext))
63	mode := cipher.NewCBCEncrypter(block, iv)
64	mode.CryptBlocks(ciphertext, plaintext)
65
66	if !bytes.Equal(ciphertext, expectedCiphertext) {
67		panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n  %s != %s\n",
68			count,
69			hex.EncodeToString(expectedCiphertext),
70			hex.EncodeToString(ciphertext)))
71	}
72}
73
74type cfbVerifier struct{}
75
76func (o cfbVerifier) validate(count string, key, iv, plaintext, expectedCiphertext []byte) {
77	block, err := cast5.NewCipher(key)
78	if err != nil {
79		panic(err)
80	}
81
82	ciphertext := make([]byte, len(plaintext))
83	stream := cipher.NewCFBEncrypter(block, iv)
84	stream.XORKeyStream(ciphertext, plaintext)
85
86	if !bytes.Equal(ciphertext, expectedCiphertext) {
87		panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n  %s != %s\n",
88			count,
89			hex.EncodeToString(expectedCiphertext),
90			hex.EncodeToString(ciphertext)))
91	}
92}
93
94type ctrVerifier struct{}
95
96func (o ctrVerifier) validate(count string, key, iv, plaintext, expectedCiphertext []byte) {
97	block, err := cast5.NewCipher(key)
98	if err != nil {
99		panic(err)
100	}
101
102	ciphertext := make([]byte, len(plaintext))
103	stream := cipher.NewCTR(block, iv)
104	stream.XORKeyStream(ciphertext, plaintext)
105
106	if !bytes.Equal(ciphertext, expectedCiphertext) {
107		panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n  %s != %s\n",
108			count,
109			hex.EncodeToString(expectedCiphertext),
110			hex.EncodeToString(ciphertext)))
111	}
112}
113
114func validateVectors(verifier vectorVerifier, filename string) {
115	vectors, err := os.Open(filename)
116	if err != nil {
117		panic(err)
118	}
119	defer vectors.Close()
120
121	var segments []string
122	var vector *vectorArgs
123
124	scanner := bufio.NewScanner(vectors)
125	for scanner.Scan() {
126		segments = strings.Split(scanner.Text(), " = ")
127
128		switch {
129		case strings.ToUpper(segments[0]) == "COUNT":
130			if vector != nil {
131				verifier.validate(vector.count,
132					unhexlify(vector.key),
133					unhexlify(vector.iv),
134					unhexlify(vector.plaintext),
135					unhexlify(vector.ciphertext))
136			}
137			vector = &vectorArgs{count: segments[1]}
138		case strings.ToUpper(segments[0]) == "IV":
139			vector.iv = segments[1][:16]
140		case strings.ToUpper(segments[0]) == "KEY":
141			vector.key = segments[1]
142		case strings.ToUpper(segments[0]) == "PLAINTEXT":
143			vector.plaintext = segments[1]
144		case strings.ToUpper(segments[0]) == "CIPHERTEXT":
145			vector.ciphertext = segments[1]
146		}
147	}
148
149}
150
151func main() {
152	validateVectors(ofbVerifier{},
153		"vectors/cryptography_vectors/ciphers/CAST5/cast5-ofb.txt")
154	fmt.Println("OFB OK.")
155	validateVectors(cfbVerifier{},
156		"vectors/cryptography_vectors/ciphers/CAST5/cast5-cfb.txt")
157	fmt.Println("CFB OK.")
158	validateVectors(cbcVerifier{},
159		"vectors/cryptography_vectors/ciphers/CAST5/cast5-cbc.txt")
160	fmt.Println("CBC OK.")
161	validateVectors(ctrVerifier{},
162		"vectors/cryptography_vectors/ciphers/CAST5/cast5-ctr.txt")
163	fmt.Println("CTR OK.")
164}
165