1package main 2 3import ( 4 "bufio" 5 "bytes" 6 "crypto/rc4" 7 "encoding/hex" 8 "fmt" 9 "os" 10 "strconv" 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 offset uint64 25 key string 26 plaintext string 27 ciphertext string 28} 29 30type vectorVerifier interface { 31 validate(count string, offset uint64, key, plaintext, expectedCiphertext []byte) 32} 33 34type arc4Verifier struct{} 35 36func (o arc4Verifier) validate(count string, offset uint64, key, plaintext, expectedCiphertext []byte) { 37 if offset%16 != 0 || len(plaintext) != 16 || len(expectedCiphertext) != 16 { 38 panic(fmt.Errorf("Unexpected input value encountered: offset=%v; len(plaintext)=%v; len(expectedCiphertext)=%v", 39 offset, 40 len(plaintext), 41 len(expectedCiphertext))) 42 } 43 stream, err := rc4.NewCipher(key) 44 if err != nil { 45 panic(err) 46 } 47 48 var currentOffset uint64 = 0 49 ciphertext := make([]byte, len(plaintext)) 50 for currentOffset <= offset { 51 stream.XORKeyStream(ciphertext, plaintext) 52 currentOffset += uint64(len(plaintext)) 53 } 54 if !bytes.Equal(ciphertext, expectedCiphertext) { 55 panic(fmt.Errorf("vector mismatch @ COUNT = %s:\n %s != %s\n", 56 count, 57 hex.EncodeToString(expectedCiphertext), 58 hex.EncodeToString(ciphertext))) 59 } 60} 61 62func validateVectors(verifier vectorVerifier, filename string) { 63 vectors, err := os.Open(filename) 64 if err != nil { 65 panic(err) 66 } 67 defer vectors.Close() 68 69 var segments []string 70 var vector *vectorArgs 71 72 scanner := bufio.NewScanner(vectors) 73 for scanner.Scan() { 74 segments = strings.Split(scanner.Text(), " = ") 75 76 switch { 77 case strings.ToUpper(segments[0]) == "COUNT": 78 if vector != nil { 79 verifier.validate(vector.count, 80 vector.offset, 81 unhexlify(vector.key), 82 unhexlify(vector.plaintext), 83 unhexlify(vector.ciphertext)) 84 } 85 vector = &vectorArgs{count: segments[1]} 86 case strings.ToUpper(segments[0]) == "OFFSET": 87 vector.offset, err = strconv.ParseUint(segments[1], 10, 64) 88 if err != nil { 89 panic(err) 90 } 91 case strings.ToUpper(segments[0]) == "KEY": 92 vector.key = segments[1] 93 case strings.ToUpper(segments[0]) == "PLAINTEXT": 94 vector.plaintext = segments[1] 95 case strings.ToUpper(segments[0]) == "CIPHERTEXT": 96 vector.ciphertext = segments[1] 97 } 98 } 99 if vector != nil { 100 verifier.validate(vector.count, 101 vector.offset, 102 unhexlify(vector.key), 103 unhexlify(vector.plaintext), 104 unhexlify(vector.ciphertext)) 105 } 106} 107 108func main() { 109 validateVectors(arc4Verifier{}, "vectors/cryptography_vectors/ciphers/ARC4/arc4.txt") 110 fmt.Println("ARC4 OK.") 111} 112