| package main |
| |
| import ( |
| "bufio" |
| "bytes" |
| "crypto/rc4" |
| "encoding/hex" |
| "fmt" |
| "os" |
| "strconv" |
| "strings" |
| ) |
| |
| func unhexlify(s string) []byte { |
| bytes, err := hex.DecodeString(s) |
| if err != nil { |
| panic(err) |
| } |
| return bytes |
| } |
| |
| type vectorArgs struct { |
| count string |
| offset uint64 |
| key string |
| plaintext string |
| ciphertext string |
| } |
| |
| type vectorVerifier interface { |
| validate(count string, offset uint64, key, plaintext, expectedCiphertext []byte) |
| } |
| |
| type arc4Verifier struct{} |
| |
| func (o arc4Verifier) validate(count string, offset uint64, key, plaintext, expectedCiphertext []byte) { |
| if offset%16 != 0 || len(plaintext) != 16 || len(expectedCiphertext) != 16 { |
| panic(fmt.Errorf("Unexpected input value encountered: offset=%v; len(plaintext)=%v; len(expectedCiphertext)=%v", |
| offset, |
| len(plaintext), |
| len(expectedCiphertext))) |
| } |
| stream, err := rc4.NewCipher(key) |
| if err != nil { |
| panic(err) |
| } |
| |
| var currentOffset uint64 = 0 |
| ciphertext := make([]byte, len(plaintext)) |
| for currentOffset <= offset { |
| stream.XORKeyStream(ciphertext, plaintext) |
| currentOffset += uint64(len(plaintext)) |
| } |
| if !bytes.Equal(ciphertext, expectedCiphertext) { |
| panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n %s != %s\n", |
| count, |
| hex.EncodeToString(expectedCiphertext), |
| hex.EncodeToString(ciphertext))) |
| } |
| } |
| |
| func validateVectors(verifier vectorVerifier, filename string) { |
| vectors, err := os.Open(filename) |
| if err != nil { |
| panic(err) |
| } |
| defer vectors.Close() |
| |
| var segments []string |
| var vector *vectorArgs |
| |
| scanner := bufio.NewScanner(vectors) |
| for scanner.Scan() { |
| segments = strings.Split(scanner.Text(), " = ") |
| |
| switch { |
| case strings.ToUpper(segments[0]) == "COUNT": |
| if vector != nil { |
| verifier.validate(vector.count, |
| vector.offset, |
| unhexlify(vector.key), |
| unhexlify(vector.plaintext), |
| unhexlify(vector.ciphertext)) |
| } |
| vector = &vectorArgs{count: segments[1]} |
| case strings.ToUpper(segments[0]) == "OFFSET": |
| vector.offset, err = strconv.ParseUint(segments[1], 10, 64) |
| if err != nil { |
| panic(err) |
| } |
| case strings.ToUpper(segments[0]) == "KEY": |
| vector.key = segments[1] |
| case strings.ToUpper(segments[0]) == "PLAINTEXT": |
| vector.plaintext = segments[1] |
| case strings.ToUpper(segments[0]) == "CIPHERTEXT": |
| vector.ciphertext = segments[1] |
| } |
| } |
| if vector != nil { |
| verifier.validate(vector.count, |
| vector.offset, |
| unhexlify(vector.key), |
| unhexlify(vector.plaintext), |
| unhexlify(vector.ciphertext)) |
| } |
| } |
| |
| func main() { |
| validateVectors(arc4Verifier{}, "vectors/cryptography_vectors/ciphers/ARC4/arc4.txt") |
| fmt.Println("ARC4 OK.") |
| } |