aboutsummaryrefslogtreecommitdiffstats
path: root/docs/development
diff options
context:
space:
mode:
authorEhren Kret <ehren.kret@gmail.com>2015-11-28 02:16:15 -0800
committerEhren Kret <ehren.kret@gmail.com>2015-11-28 02:22:19 -0800
commitd01c20fb29dc3a6ba53accd3bd561c05715f62c9 (patch)
tree133958e1e32ba0c5ddd252f408f3a8daaf302ad3 /docs/development
parent7f7fab8f2bb48056149e2717f440b13c3ce5fcf8 (diff)
downloadcryptography-d01c20fb29dc3a6ba53accd3bd561c05715f62c9.tar.gz
cryptography-d01c20fb29dc3a6ba53accd3bd561c05715f62c9.tar.bz2
cryptography-d01c20fb29dc3a6ba53accd3bd561c05715f62c9.zip
Add support for 160 bit ARC4 keys
Diffstat (limited to 'docs/development')
-rw-r--r--docs/development/custom-vectors/arc4.rst30
-rw-r--r--docs/development/custom-vectors/arc4/generate_arc4.py89
-rw-r--r--docs/development/custom-vectors/arc4/verify_arc4.go111
3 files changed, 230 insertions, 0 deletions
diff --git a/docs/development/custom-vectors/arc4.rst b/docs/development/custom-vectors/arc4.rst
new file mode 100644
index 00000000..ed8cd548
--- /dev/null
+++ b/docs/development/custom-vectors/arc4.rst
@@ -0,0 +1,30 @@
+ARC4 vector creation
+====================
+
+This page documents the code that was used to generate the ARC4 test
+vectors for key lengths not available in RFC 6229. All the vectors
+were generated using OpenSSL and verified with Go.
+
+Creation
+--------
+
+``cryptography`` was modified to support ARC4 key lengths not listed
+in RFC 6229. Then the following Python script was run to generate the
+vector files.
+
+.. literalinclude:: /development/custom-vectors/arc4/generate_arc4.py
+
+Download link: :download:`generate_arc4.py
+</development/custom-vectors/arc4/generate_arc4.py>`
+
+
+Verification
+------------
+
+The following Go code was used to verify the vectors.
+
+.. literalinclude:: /development/custom-vectors/arc4/verify_arc4.go
+ :language: go
+
+Download link: :download:`verify_arc4.go
+</development/custom-vectors/arc4/verify_arc4.go>`
diff --git a/docs/development/custom-vectors/arc4/generate_arc4.py b/docs/development/custom-vectors/arc4/generate_arc4.py
new file mode 100644
index 00000000..093bb49d
--- /dev/null
+++ b/docs/development/custom-vectors/arc4/generate_arc4.py
@@ -0,0 +1,89 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import binascii
+
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import ciphers
+from cryptography.hazmat.primitives.ciphers import algorithms
+
+
+_RFC6229_KEY_MATERIALS = [
+ (True, 8*'0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20'),
+ (False, 8*'1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a')
+]
+
+
+_RFC6229_OFFSETS = [
+ 0,
+ 16,
+ 240,
+ 256,
+ 496,
+ 512,
+ 752,
+ 768,
+ 1008,
+ 1024,
+ 1520,
+ 1536,
+ 2032,
+ 2048,
+ 3056,
+ 3072,
+ 4080,
+ 4096
+]
+
+
+_SIZES_TO_GENERATE = [
+ 160
+]
+
+
+def _key_for_size(size, keyinfo):
+ msb, key = keyinfo
+ if msb:
+ return key[:size//4]
+ else:
+ return key[-size//4:]
+
+
+def _build_vectors():
+ count = 0
+ output = []
+ key = None
+ plaintext = binascii.unhexlify(32*'0')
+ for size in _SIZES_TO_GENERATE:
+ for keyinfo in _RFC6229_KEY_MATERIALS:
+ key = _key_for_size(size, keyinfo)
+ cipher = ciphers.Cipher(algorithms.ARC4(binascii.unhexlify(key)), None, default_backend())
+ encryptor = cipher.encryptor()
+ current_offset = 0
+ for offset in _RFC6229_OFFSETS:
+ if offset % 16 != 0:
+ raise ValueError("Offset {} is not evenly divisible by 16".format(offset))
+ while current_offset < offset:
+ encryptor.update(plaintext)
+ current_offset += len(plaintext)
+ output.append("\nCOUNT = {}".format(count))
+ count += 1
+ output.append("KEY = {}".format(key))
+ output.append("OFFSET = {}".format(offset))
+ output.append("PLAINTEXT = {}".format(binascii.hexlify(plaintext)))
+ output.append("CIPHERTEXT = {}".format(binascii.hexlify(encryptor.update(plaintext))))
+ current_offset += len(plaintext)
+ assert not encryptor.finalize()
+ return "\n".join(output)
+
+
+def _write_file(data, filename):
+ with open(filename, 'w') as f:
+ f.write(data)
+
+
+if __name__ == '__main__':
+ _write_file(_build_vectors(), 'arc4.txt')
diff --git a/docs/development/custom-vectors/arc4/verify_arc4.go b/docs/development/custom-vectors/arc4/verify_arc4.go
new file mode 100644
index 00000000..508fe980
--- /dev/null
+++ b/docs/development/custom-vectors/arc4/verify_arc4.go
@@ -0,0 +1,111 @@
+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.")
+}