aboutsummaryrefslogtreecommitdiffstats
path: root/docs/development/custom-vectors
diff options
context:
space:
mode:
Diffstat (limited to 'docs/development/custom-vectors')
-rw-r--r--docs/development/custom-vectors/arc4.rst30
-rw-r--r--docs/development/custom-vectors/arc4/generate_arc4.py98
-rw-r--r--docs/development/custom-vectors/arc4/verify_arc4.go111
-rw-r--r--docs/development/custom-vectors/cast5/generate_cast5.py44
-rw-r--r--docs/development/custom-vectors/cast5/verify_cast5.go2
-rw-r--r--docs/development/custom-vectors/hkdf.rst28
-rw-r--r--docs/development/custom-vectors/hkdf/generate_hkdf.py39
-rw-r--r--docs/development/custom-vectors/hkdf/verify_hkdf.go69
-rw-r--r--docs/development/custom-vectors/idea.rst2
-rw-r--r--docs/development/custom-vectors/idea/generate_idea.py1
-rw-r--r--docs/development/custom-vectors/rsa-oaep-sha2.rst56
-rw-r--r--docs/development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java416
-rw-r--r--docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py128
-rw-r--r--docs/development/custom-vectors/secp256k1.rst2
-rw-r--r--docs/development/custom-vectors/secp256k1/generate_secp256k1.py1
-rw-r--r--docs/development/custom-vectors/secp256k1/verify_secp256k1.py4
-rw-r--r--docs/development/custom-vectors/seed.rst2
-rw-r--r--docs/development/custom-vectors/seed/generate_seed.py1
18 files changed, 1007 insertions, 27 deletions
diff --git a/docs/development/custom-vectors/arc4.rst b/docs/development/custom-vectors/arc4.rst
new file mode 100644
index 00000000..5b1b65d5
--- /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..3dee44a3
--- /dev/null
+++ b/docs/development/custom-vectors/arc4/generate_arc4.py
@@ -0,0 +1,98 @@
+# 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.")
+}
diff --git a/docs/development/custom-vectors/cast5/generate_cast5.py b/docs/development/custom-vectors/cast5/generate_cast5.py
index 20f35179..ce046b0f 100644
--- a/docs/development/custom-vectors/cast5/generate_cast5.py
+++ b/docs/development/custom-vectors/cast5/generate_cast5.py
@@ -23,33 +23,34 @@ def encrypt(mode, key, iv, plaintext):
def build_vectors(mode, filename):
- vector_file = open(filename, "r")
-
count = 0
output = []
key = None
iv = None
plaintext = None
- for line in vector_file:
- line = line.strip()
- if line.startswith("KEY"):
- if count != 0:
- output.append("CIPHERTEXT = {}".format(
- encrypt(mode, key, iv, plaintext))
- )
- output.append("\nCOUNT = {}".format(count))
- count += 1
- name, key = line.split(" = ")
- output.append("KEY = {}".format(key))
- elif line.startswith("IV"):
- name, iv = line.split(" = ")
- iv = iv[0:16]
- output.append("IV = {}".format(iv))
- elif line.startswith("PLAINTEXT"):
- name, plaintext = line.split(" = ")
- output.append("PLAINTEXT = {}".format(plaintext))
- output.append("CIPHERTEXT = {}".format(encrypt(mode, key, iv, plaintext)))
+ with open(filename, "r") as vector_file:
+ for line in vector_file:
+ line = line.strip()
+ if line.startswith("KEY"):
+ if count != 0:
+ output.append("CIPHERTEXT = {}".format(
+ encrypt(mode, key, iv, plaintext))
+ )
+ output.append("\nCOUNT = {}".format(count))
+ count += 1
+ name, key = line.split(" = ")
+ output.append("KEY = {}".format(key))
+ elif line.startswith("IV"):
+ name, iv = line.split(" = ")
+ iv = iv[0:16]
+ output.append("IV = {}".format(iv))
+ elif line.startswith("PLAINTEXT"):
+ name, plaintext = line.split(" = ")
+ output.append("PLAINTEXT = {}".format(plaintext))
+ output.append(
+ "CIPHERTEXT = {}".format(encrypt(mode, key, iv, plaintext))
+ )
return "\n".join(output)
@@ -57,6 +58,7 @@ def write_file(data, filename):
with open(filename, "w") as f:
f.write(data)
+
cbc_path = "tests/hazmat/primitives/vectors/ciphers/AES/CBC/CBCMMT128.rsp"
write_file(build_vectors(modes.CBC, cbc_path), "cast5-cbc.txt")
ofb_path = "tests/hazmat/primitives/vectors/ciphers/AES/OFB/OFBMMT128.rsp"
diff --git a/docs/development/custom-vectors/cast5/verify_cast5.go b/docs/development/custom-vectors/cast5/verify_cast5.go
index cbc89a03..b2d711a9 100644
--- a/docs/development/custom-vectors/cast5/verify_cast5.go
+++ b/docs/development/custom-vectors/cast5/verify_cast5.go
@@ -3,7 +3,7 @@ package main
import (
"bufio"
"bytes"
- "code.google.com/p/go.crypto/cast5"
+ "golang.org/x/crypto/cast5"
"crypto/cipher"
"encoding/hex"
"fmt"
diff --git a/docs/development/custom-vectors/hkdf.rst b/docs/development/custom-vectors/hkdf.rst
new file mode 100644
index 00000000..6d7e8618
--- /dev/null
+++ b/docs/development/custom-vectors/hkdf.rst
@@ -0,0 +1,28 @@
+HKDF vector creation
+====================
+
+This page documents the code that was used to generate a longer
+HKDF test vector (1200 bytes) than is available in :rfc:`5869`. All
+the vectors were generated using OpenSSL and verified with Go.
+
+Creation
+--------
+
+The following Python script was run to generate the vector files.
+
+.. literalinclude:: /development/custom-vectors/hkdf/generate_hkdf.py
+
+Download link: :download:`generate_hkdf.py
+</development/custom-vectors/hkdf/generate_hkdf.py>`
+
+
+Verification
+------------
+
+The following Go code was used to verify the vectors.
+
+.. literalinclude:: /development/custom-vectors/hkdf/verify_hkdf.go
+ :language: go
+
+Download link: :download:`verify_hkdf.go
+</development/custom-vectors/hkdf/verify_hkdf.go>`
diff --git a/docs/development/custom-vectors/hkdf/generate_hkdf.py b/docs/development/custom-vectors/hkdf/generate_hkdf.py
new file mode 100644
index 00000000..8976effd
--- /dev/null
+++ b/docs/development/custom-vectors/hkdf/generate_hkdf.py
@@ -0,0 +1,39 @@
+# 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 hashes
+from cryptography.hazmat.primitives.kdf.hkdf import HKDF
+
+IKM = binascii.unhexlify(b"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
+L = 1200
+OKM = HKDF(
+ algorithm=hashes.SHA256(), length=L, salt=None, info=None,
+ backend=default_backend()
+).derive(IKM)
+
+
+def _build_vectors():
+ output = [
+ "COUNT = 0",
+ "Hash = SHA-256",
+ "IKM = " + binascii.hexlify(IKM).decode("ascii"),
+ "salt = ", "info = ",
+ "L = {}".format(L),
+ "OKM = " + binascii.hexlify(OKM).decode("ascii"),
+ ]
+ 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(), 'hkdf.txt')
diff --git a/docs/development/custom-vectors/hkdf/verify_hkdf.go b/docs/development/custom-vectors/hkdf/verify_hkdf.go
new file mode 100644
index 00000000..ddeb3d8e
--- /dev/null
+++ b/docs/development/custom-vectors/hkdf/verify_hkdf.go
@@ -0,0 +1,69 @@
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "golang.org/x/crypto/hkdf"
+ "io"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func unhexlify(s string) []byte {
+ bytes, err := hex.DecodeString(s)
+ if err != nil {
+ panic(err)
+ }
+ return bytes
+}
+
+func verifier(l uint64, ikm, okm []byte) bool {
+ hash := sha256.New
+ hkdf := hkdf.New(hash, ikm, nil, nil)
+ okmComputed := make([]byte, l)
+ io.ReadFull(hkdf, okmComputed)
+ return bytes.Equal(okmComputed, okm)
+}
+
+func validateVectors(filename string) bool {
+ vectors, err := os.Open(filename)
+ if err != nil {
+ panic(err)
+ }
+ defer vectors.Close()
+
+ var segments []string
+ var l uint64
+ var ikm, okm string
+
+ scanner := bufio.NewScanner(vectors)
+ for scanner.Scan() {
+ segments = strings.Split(scanner.Text(), " = ")
+
+ switch {
+ case strings.ToUpper(segments[0]) == "L":
+ l, err = strconv.ParseUint(segments[1], 10, 64)
+ if err != nil {
+ panic(err)
+ }
+ case strings.ToUpper(segments[0]) == "IKM":
+ ikm = segments[1]
+ case strings.ToUpper(segments[0]) == "OKM":
+ okm = segments[1]
+ }
+ }
+ return verifier(l, unhexlify(ikm), unhexlify(okm))
+}
+
+func main() {
+ if validateVectors("vectors/cryptography_vectors/KDF/hkdf-generated.txt") {
+ fmt.Println("HKDF OK.")
+ } else {
+ fmt.Println("HKDF failed.")
+ os.Exit(1)
+ }
+}
diff --git a/docs/development/custom-vectors/idea.rst b/docs/development/custom-vectors/idea.rst
index 336cdf01..758a108e 100644
--- a/docs/development/custom-vectors/idea.rst
+++ b/docs/development/custom-vectors/idea.rst
@@ -29,4 +29,4 @@ project's Python bindings.
Download link: :download:`verify_idea.py
</development/custom-vectors/idea/verify_idea.py>`
-.. _`Botan`: http://botan.randombit.net
+.. _`Botan`: https://botan.randombit.net
diff --git a/docs/development/custom-vectors/idea/generate_idea.py b/docs/development/custom-vectors/idea/generate_idea.py
index c9f94024..2eb6996e 100644
--- a/docs/development/custom-vectors/idea/generate_idea.py
+++ b/docs/development/custom-vectors/idea/generate_idea.py
@@ -52,6 +52,7 @@ def write_file(data, filename):
with open(filename, "w") as f:
f.write(data)
+
CBC_PATH = "tests/hazmat/primitives/vectors/ciphers/AES/CBC/CBCMMT128.rsp"
write_file(build_vectors(modes.CBC, CBC_PATH), "idea-cbc.txt")
OFB_PATH = "tests/hazmat/primitives/vectors/ciphers/AES/OFB/OFBMMT128.rsp"
diff --git a/docs/development/custom-vectors/rsa-oaep-sha2.rst b/docs/development/custom-vectors/rsa-oaep-sha2.rst
new file mode 100644
index 00000000..36f256d7
--- /dev/null
+++ b/docs/development/custom-vectors/rsa-oaep-sha2.rst
@@ -0,0 +1,56 @@
+RSA OAEP SHA2 vector creation
+=============================
+
+This page documents the code that was used to generate the RSA OAEP SHA2
+test vectors as well as code used to verify them against another
+implementation.
+
+
+Creation
+--------
+
+``cryptography`` was modified to allow the use of SHA2 in OAEP encryption. Then
+the following python script was run to generate the vector files.
+
+.. literalinclude:: /development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py
+
+Download link: :download:`generate_rsa_oaep_sha2.py
+</development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py>`
+
+
+Verification
+------------
+
+A Java 8 program was written using `Bouncy Castle`_ to load and verify the test
+vectors.
+
+
+.. literalinclude:: /development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java
+
+Download link: :download:`VerifyRSAOAEPSHA2.java
+</development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java>`
+
+Using the Verifier
+------------------
+
+Download and install the `Java 8 SDK`_. Initial verification was performed
+using ``jdk-8u77-macosx-x64.dmg``.
+
+Download the latest `Bouncy Castle`_ JAR. Initial verification was performed
+using ``bcprov-jdk15on-154.jar``.
+
+Set the ``-classpath`` to include the Bouncy Castle jar and the path to
+``VerifyRSAOAEPSHA2.java`` and compile the program.
+
+.. code-block:: console
+
+ $ javac -classpath ~/Downloads/bcprov-jdk15on-154.jar:./ VerifyRSAOAEPSHA2.java
+
+Finally, run the program with the path to the SHA-2 vectors:
+
+.. code-block:: console
+
+ $ java -classpath ~/Downloads/bcprov-jdk15on-154.jar:./ VerifyRSAOAEPSHA2
+
+.. _`Bouncy Castle`: https://www.bouncycastle.org/
+.. _`Java 8 SDK`: https://www.oracle.com/technetwork/java/javase/downloads/index.html
diff --git a/docs/development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java b/docs/development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java
new file mode 100644
index 00000000..e1bfd3d1
--- /dev/null
+++ b/docs/development/custom-vectors/rsa-oaep-sha2/VerifyRSAOAEPSHA2.java
@@ -0,0 +1,416 @@
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+import javax.xml.bind.DatatypeConverter;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+class TestVectorData {
+ public BigInteger pub_key_modulus;
+ public BigInteger pub_key_exponent;
+ public BigInteger priv_key_public_exponent;
+ public BigInteger priv_key_modulus;
+ public BigInteger priv_key_exponent;
+ public BigInteger priv_key_prime_1;
+ public BigInteger priv_key_prime_2;
+ public BigInteger priv_key_prime_exponent_1;
+ public BigInteger priv_key_prime_exponent_2;
+ public BigInteger priv_key_coefficient;
+ public byte[] plaintext;
+ public byte[] ciphertext;
+}
+
+class TestVectorLoader {
+ private static final String FILE_HEADER = "# RSA OAEP SHA2 vectors built";
+ private static final String EXAMPLE_HEADER = "# =====";
+ private static final String EXAMPLE = "# Example";
+ private static final String PUBLIC_KEY = "# Public key";
+ private static final String PUB_MODULUS = "# Modulus:";
+ private static final String PUB_EXPONENT = "# Exponent:";
+ private static final String PRIVATE_KEY = "# Private key";
+ private static final String PRIV_MODULUS = "# Modulus:";
+ private static final String PRIV_PUBLIC_EXPONENT = "# Public exponent:";
+ private static final String PRIV_EXPONENT = "# Exponent:";
+ private static final String PRIV_PRIME_1 = "# Prime 1:";
+ private static final String PRIV_PRIME_2 = "# Prime 2:";
+ private static final String PRIV_PRIME_EXPONENT_1 = "# Prime exponent 1:";
+ private static final String PRIV_PRIME_EXPONENT_2 = "# Prime exponent 2:";
+ private static final String PRIV_COEFFICIENT = "# Coefficient:";
+ private static final String OAEP_EXAMPLE_HEADER = "# OAEP Example";
+ private static final String MESSAGE = "# Message:";
+ private static final String ENCRYPTION = "# Encryption:";
+
+ private BufferedReader m_reader = null;
+ private FileReader m_file_reader = null;
+ private TestVectorData m_data = null;
+
+ TestVectorLoader() {
+
+ }
+
+ protected void finalize() {
+ close();
+ }
+
+ public void open(String path) throws IOException {
+ close();
+ m_file_reader = new FileReader(path);
+ m_reader = new BufferedReader(m_file_reader);
+ m_data = new TestVectorData();
+ }
+
+ public void close() {
+ try {
+ if (m_reader != null) {
+ m_reader.close();
+ m_reader = null;
+ }
+ if (m_file_reader != null) {
+ m_file_reader.close();
+ m_file_reader = null;
+ }
+ m_data = null;
+ } catch (IOException e) {
+ System.out.println("Exception closing files");
+ e.printStackTrace();
+ }
+ }
+
+ public TestVectorData loadNextTest() throws IOException {
+ if (m_file_reader == null || m_reader == null || m_data == null) {
+ throw new IOException("A test vector file must be opened first");
+ }
+
+ String line = m_reader.readLine();
+
+ if (line == null) {
+ // end of file
+ return null;
+ }
+
+ if (line.startsWith(FILE_HEADER)) {
+ // start of file
+ skipFileHeader(m_reader);
+ line = m_reader.readLine();
+ }
+
+ if (line.startsWith(OAEP_EXAMPLE_HEADER)) {
+ // Next example, keep existing keys and load next message
+ loadMessage(m_reader, m_data);
+ return m_data;
+ }
+
+ // otherwise it's a new example
+ if (!line.startsWith(EXAMPLE_HEADER)) {
+ throw new IOException("Test Header Missing");
+ }
+ startNewTest(m_reader);
+ m_data = new TestVectorData();
+
+ line = m_reader.readLine();
+ if (!line.startsWith(PUBLIC_KEY))
+ throw new IOException("Public Key Missing");
+ loadPublicKey(m_reader, m_data);
+
+ line = m_reader.readLine();
+ if (!line.startsWith(PRIVATE_KEY))
+ throw new IOException("Private Key Missing");
+ loadPrivateKey(m_reader, m_data);
+
+ line = m_reader.readLine();
+ if (!line.startsWith(OAEP_EXAMPLE_HEADER))
+ throw new IOException("Message Missing");
+ loadMessage(m_reader, m_data);
+
+ return m_data;
+ }
+
+ private byte[] unhexlify(String line) {
+ byte[] bytes = DatatypeConverter.parseHexBinary(line);
+ return bytes;
+ }
+
+ private BigInteger readBigInteger(BufferedReader br) throws IOException {
+ return new BigInteger(br.readLine(), 16);
+ }
+
+ private void skipFileHeader(BufferedReader br) throws IOException {
+ br.readLine(); // # # Derived from the NIST OAEP SHA1 vectors
+ br.readLine(); // # # Verified against the Bouncy Castle OAEP SHA2 implementation
+ br.readLine(); // #
+ }
+
+ private void startNewTest(BufferedReader br) throws IOException {
+ String line = br.readLine();
+ if (!line.startsWith(EXAMPLE))
+ throw new IOException("Example Header Missing");
+ }
+
+ private void loadPublicKey(BufferedReader br, TestVectorData data) throws IOException {
+ String line = br.readLine();
+ if (!line.startsWith(PUB_MODULUS))
+ throw new IOException("Public Key Modulus Missing");
+ data.pub_key_modulus = readBigInteger(br);
+
+ line = br.readLine();
+ if (!line.startsWith(PUB_EXPONENT))
+ throw new IOException("Public Key Exponent Missing");
+ data.pub_key_exponent = readBigInteger(br);
+ }
+
+ private void loadPrivateKey(BufferedReader br, TestVectorData data) throws IOException {
+ String line = br.readLine();
+ if (!line.startsWith(PRIV_MODULUS))
+ throw new IOException("Private Key Modulus Missing");
+ data.priv_key_modulus = readBigInteger(br);
+
+ line = br.readLine();
+ if (!line.startsWith(PRIV_PUBLIC_EXPONENT))
+ throw new IOException("Private Key Public Exponent Missing");
+ data.priv_key_public_exponent = readBigInteger(br);
+
+ line = br.readLine();
+ if (!line.startsWith(PRIV_EXPONENT))
+ throw new IOException("Private Key Exponent Missing");
+ data.priv_key_exponent = readBigInteger(br);
+
+ line = br.readLine();
+ if (!line.startsWith(PRIV_PRIME_1))
+ throw new IOException("Private Key Prime 1 Missing");
+ data.priv_key_prime_1 = readBigInteger(br);
+
+ line = br.readLine();
+ if (!line.startsWith(PRIV_PRIME_2))
+ throw new IOException("Private Key Prime 2 Missing");
+ data.priv_key_prime_2 = readBigInteger(br);
+
+ line = br.readLine();
+ if (!line.startsWith(PRIV_PRIME_EXPONENT_1))
+ throw new IOException("Private Key Prime Exponent 1 Missing");
+ data.priv_key_prime_exponent_1 = readBigInteger(br);
+
+ line = br.readLine();
+ if (!line.startsWith(PRIV_PRIME_EXPONENT_2))
+ throw new IOException("Private Key Prime Exponent 2 Missing");
+ data.priv_key_prime_exponent_2 = readBigInteger(br);
+
+ line = br.readLine();
+ if (!line.startsWith(PRIV_COEFFICIENT))
+ throw new IOException("Private Key Coefficient Missing");
+ data.priv_key_coefficient = readBigInteger(br);
+ }
+
+ private void loadMessage(BufferedReader br, TestVectorData data) throws IOException {
+ String line = br.readLine();
+ if (!line.startsWith(MESSAGE))
+ throw new IOException("Plaintext Missing");
+ data.plaintext = unhexlify(br.readLine());
+
+ line = br.readLine();
+ if (!line.startsWith(ENCRYPTION))
+ throw new IOException("Ciphertext Missing");
+ data.ciphertext = unhexlify(br.readLine());
+ }
+
+}
+
+public class VerifyRSAOAEPSHA2 {
+
+ public enum SHAHash {
+ SHA1, SHA224, SHA256, SHA384, SHA512
+ }
+
+ private SHAHash m_mgf1_hash;
+ private SHAHash m_alg_hash;
+ private Cipher m_cipher;
+ private PrivateKey m_private_key;
+ private AlgorithmParameters m_algo_param;
+
+ VerifyRSAOAEPSHA2(SHAHash mgf1_hash, SHAHash alg_hash, TestVectorData test_data) throws Exception {
+
+ m_mgf1_hash = mgf1_hash;
+ m_alg_hash = alg_hash;
+
+ MGF1ParameterSpec mgf1_spec = getMGF1ParameterSpec(m_mgf1_hash);
+ AlgorithmParameterSpec algo_param_spec = getAlgorithmParameterSpec(m_alg_hash, mgf1_spec);
+
+ m_algo_param = AlgorithmParameters.getInstance("OAEP");
+ m_algo_param.init(algo_param_spec);
+
+ m_private_key = loadPrivateKey(test_data);
+
+ m_cipher = getCipher(m_alg_hash);
+ }
+
+ private Cipher getCipher(SHAHash alg_hash) throws GeneralSecurityException {
+ Cipher cipher = null;
+
+ switch (alg_hash) {
+
+ case SHA1:
+ cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding", "BC");
+ break;
+
+ case SHA224:
+ cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-224andMGF1Padding", "BC");
+ break;
+
+ case SHA256:
+ cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding", "BC");
+ break;
+
+ case SHA384:
+ cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-384andMGF1Padding", "BC");
+ break;
+
+ case SHA512:
+ cipher = Cipher.getInstance("RSA/ECB/OAEPwithSHA-512andMGF1Padding", "BC");
+ break;
+ }
+
+ return cipher;
+ }
+
+ private MGF1ParameterSpec getMGF1ParameterSpec(SHAHash mgf1_hash) {
+ MGF1ParameterSpec mgf1 = null;
+
+ switch (mgf1_hash) {
+
+ case SHA1:
+ mgf1 = MGF1ParameterSpec.SHA1;
+ break;
+ case SHA224:
+ mgf1 = MGF1ParameterSpec.SHA224;
+ break;
+
+ case SHA256:
+ mgf1 = MGF1ParameterSpec.SHA256;
+ break;
+
+ case SHA384:
+ mgf1 = MGF1ParameterSpec.SHA384;
+ break;
+
+ case SHA512:
+ mgf1 = MGF1ParameterSpec.SHA512;
+ break;
+ }
+
+ return mgf1;
+ }
+
+ private AlgorithmParameterSpec getAlgorithmParameterSpec(SHAHash alg_hash, MGF1ParameterSpec mgf1_spec) {
+
+ OAEPParameterSpec oaep_spec = null;
+
+ switch (alg_hash) {
+
+ case SHA1:
+ oaep_spec = new OAEPParameterSpec("SHA1", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
+ break;
+
+ case SHA224:
+ oaep_spec = new OAEPParameterSpec("SHA-224", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
+ break;
+
+ case SHA256:
+ oaep_spec = new OAEPParameterSpec("SHA-256", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
+ break;
+
+ case SHA384:
+ oaep_spec = new OAEPParameterSpec("SHA-384", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
+ break;
+
+ case SHA512:
+ oaep_spec = new OAEPParameterSpec("SHA-512", "MGF1", mgf1_spec, PSource.PSpecified.DEFAULT);
+ break;
+ }
+
+ return oaep_spec;
+ }
+
+ private PrivateKey loadPrivateKey(TestVectorData test_data) throws Exception {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+
+ RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(test_data.priv_key_modulus, test_data.priv_key_exponent);
+
+ return kf.generatePrivate(keySpec);
+ }
+
+ public void testDecrypt(byte[] plaintext, byte[] ciphertext) throws Exception {
+ System.out.println("Verifying OAEP with mgf1_hash: " + m_mgf1_hash + " alg_hash: " + m_alg_hash + " - "
+ + ciphertext.length + " bytes ciphertext - "
+ + plaintext.length + " bytes plaintext");
+
+ m_cipher.init(Cipher.DECRYPT_MODE, m_private_key, m_algo_param);
+ byte[] java_plaintext = m_cipher.doFinal(ciphertext);
+
+ if (Arrays.equals(java_plaintext, plaintext) == false) {
+ throw new Exception("Verification failure - plaintext does not match after decryption.");
+ }
+ }
+
+ public static void main(String[] args) {
+ Security.addProvider(new BouncyCastleProvider());
+
+ // assume current directory if no path given on command line
+ String vector_path = "./vectors/cryptography_vectors/asymmetric/RSA/oaep-custom";
+
+ if (args.length > 0) {
+ vector_path = args[0];
+ }
+
+ System.out.println("Vector file path: " + vector_path);
+
+ try {
+ // loop over each combination of hash loading the vector file
+ // to verify for each
+ for (SHAHash mgf1_hash : SHAHash.values()) {
+ for (SHAHash alg_hash : SHAHash.values()) {
+ if (mgf1_hash.name().toLowerCase().equals("sha1") &&
+ alg_hash.name().toLowerCase().equals("sha1")) {
+ continue;
+ }
+ String filename = "oaep-" + mgf1_hash.name().toLowerCase() +
+ "-" + alg_hash.name().toLowerCase() + ".txt";
+
+ System.out.println("Loading " + filename + "...");
+
+ TestVectorLoader loader = new TestVectorLoader();
+ loader.open(vector_path + filename);
+
+ TestVectorData test_data;
+
+ // load each test in the file and verify
+ while ((test_data = loader.loadNextTest()) != null) {
+ VerifyRSAOAEPSHA2 verify = new VerifyRSAOAEPSHA2(mgf1_hash, alg_hash, test_data);
+ verify.testDecrypt(test_data.plaintext, test_data.ciphertext);
+ }
+
+ System.out.println("Verifying " + filename + " completed successfully.");
+ }
+ }
+
+ System.out.println("All verification completed successfully");
+
+ } catch (Exception e) {
+ // if any exception is thrown the verification has failed
+ e.printStackTrace();
+ System.out.println("Verification Failed!");
+ }
+ }
+}
diff --git a/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py b/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py
new file mode 100644
index 00000000..bd5148f5
--- /dev/null
+++ b/docs/development/custom-vectors/rsa-oaep-sha2/generate_rsa_oaep_sha2.py
@@ -0,0 +1,128 @@
+# 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
+import itertools
+import os
+
+from cryptography.hazmat.backends.openssl.backend import backend
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import padding, rsa
+
+from tests.utils import load_pkcs1_vectors, load_vectors_from_file
+
+
+def build_vectors(mgf1alg, hashalg, filename):
+ vectors = load_vectors_from_file(filename, load_pkcs1_vectors)
+
+ output = []
+ for vector in vectors:
+ # RSA keys for this must be long enough to accommodate the length of
+ # the underlying hash function. This means we can't use the keys from
+ # the sha1 test vectors for sha512 tests because 1024-bit keys are too
+ # small. Instead we parse the vectors for the test cases, then
+ # generate our own 2048-bit keys for each.
+ private, _ = vector
+ skey = rsa.generate_private_key(65537, 2048, backend)
+ pn = skey.private_numbers()
+ examples = private["examples"]
+ output.append(b"# =============================================")
+ output.append(b"# Example")
+ output.append(b"# Public key")
+ output.append(b"# Modulus:")
+ output.append(format(pn.public_numbers.n, "x"))
+ output.append(b"# Exponent:")
+ output.append(format(pn.public_numbers.e, "x"))
+ output.append(b"# Private key")
+ output.append(b"# Modulus:")
+ output.append(format(pn.public_numbers.n, "x"))
+ output.append(b"# Public exponent:")
+ output.append(format(pn.public_numbers.e, "x"))
+ output.append(b"# Exponent:")
+ output.append(format(pn.d, "x"))
+ output.append(b"# Prime 1:")
+ output.append(format(pn.p, "x"))
+ output.append(b"# Prime 2:")
+ output.append(format(pn.q, "x"))
+ output.append(b"# Prime exponent 1:")
+ output.append(format(pn.dmp1, "x"))
+ output.append(b"# Prime exponent 2:")
+ output.append(format(pn.dmq1, "x"))
+ output.append(b"# Coefficient:")
+ output.append(format(pn.iqmp, "x"))
+ pkey = skey.public_key()
+ vectorkey = rsa.RSAPrivateNumbers(
+ p=private["p"],
+ q=private["q"],
+ d=private["private_exponent"],
+ dmp1=private["dmp1"],
+ dmq1=private["dmq1"],
+ iqmp=private["iqmp"],
+ public_numbers=rsa.RSAPublicNumbers(
+ e=private["public_exponent"],
+ n=private["modulus"]
+ )
+ ).private_key(backend)
+ count = 1
+
+ for example in examples:
+ message = vectorkey.decrypt(
+ binascii.unhexlify(example["encryption"]),
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ algorithm=hashes.SHA1(),
+ label=None
+ )
+ )
+ assert message == binascii.unhexlify(example["message"])
+ ct = pkey.encrypt(
+ message,
+ padding.OAEP(
+ mgf=padding.MGF1(algorithm=mgf1alg),
+ algorithm=hashalg,
+ label=None
+ )
+ )
+ output.append(
+ b"# OAEP Example {0} alg={1} mgf1={2}".format(
+ count, hashalg.name, mgf1alg.name
+ )
+ )
+ count += 1
+ output.append(b"# Message:")
+ output.append(example["message"])
+ output.append(b"# Encryption:")
+ output.append(binascii.hexlify(ct))
+
+ return b"\n".join(output)
+
+
+def write_file(data, filename):
+ with open(filename, "w") as f:
+ f.write(data)
+
+
+oaep_path = os.path.join(
+ "asymmetric", "RSA", "pkcs-1v2-1d2-vec", "oaep-vect.txt"
+)
+hashalgs = [
+ hashes.SHA1(),
+ hashes.SHA224(),
+ hashes.SHA256(),
+ hashes.SHA384(),
+ hashes.SHA512(),
+]
+for hashtuple in itertools.product(hashalgs, hashalgs):
+ if (
+ isinstance(hashtuple[0], hashes.SHA1) and
+ isinstance(hashtuple[1], hashes.SHA1)
+ ):
+ continue
+
+ write_file(
+ build_vectors(hashtuple[0], hashtuple[1], oaep_path),
+ "oaep-{0}-{1}.txt".format(hashtuple[0].name, hashtuple[1].name)
+ )
diff --git a/docs/development/custom-vectors/secp256k1.rst b/docs/development/custom-vectors/secp256k1.rst
index b19bf4e4..e0579b4f 100644
--- a/docs/development/custom-vectors/secp256k1.rst
+++ b/docs/development/custom-vectors/secp256k1.rst
@@ -29,4 +29,4 @@ the following python script was run to generate the vector files.
Download link: :download:`verify_secp256k1.py
</development/custom-vectors/secp256k1/verify_secp256k1.py>`
-.. _`pure Python ecdsa`: https://pypi.python.org/pypi/ecdsa
+.. _`pure Python ecdsa`: https://pypi.org/project/ecdsa/
diff --git a/docs/development/custom-vectors/secp256k1/generate_secp256k1.py b/docs/development/custom-vectors/secp256k1/generate_secp256k1.py
index 502a3ff6..d6a2071a 100644
--- a/docs/development/custom-vectors/secp256k1/generate_secp256k1.py
+++ b/docs/development/custom-vectors/secp256k1/generate_secp256k1.py
@@ -74,6 +74,7 @@ def write_file(lines, dest):
print(line)
print(line, file=dest)
+
source_path = os.path.join("asymmetric", "ECDSA", "FIPS_186-3", "SigGen.txt")
dest_path = os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt")
diff --git a/docs/development/custom-vectors/secp256k1/verify_secp256k1.py b/docs/development/custom-vectors/secp256k1/verify_secp256k1.py
index 3d2c25b9..b236d77f 100644
--- a/docs/development/custom-vectors/secp256k1/verify_secp256k1.py
+++ b/docs/development/custom-vectors/secp256k1/verify_secp256k1.py
@@ -6,7 +6,7 @@ from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import (
- encode_rfc6979_signature
+ encode_dss_signature
)
from tests.utils import (
@@ -27,7 +27,7 @@ def verify_one_vector(vector):
message = vector['message']
x = vector['x']
y = vector['y']
- signature = encode_rfc6979_signature(vector['r'], vector['s'])
+ signature = encode_dss_signature(vector['r'], vector['s'])
numbers = ec.EllipticCurvePublicNumbers(
x, y,
diff --git a/docs/development/custom-vectors/seed.rst b/docs/development/custom-vectors/seed.rst
index 290fb77a..8c4a7aab 100644
--- a/docs/development/custom-vectors/seed.rst
+++ b/docs/development/custom-vectors/seed.rst
@@ -29,4 +29,4 @@ project's Python bindings.
Download link: :download:`verify_seed.py
</development/custom-vectors/seed/verify_seed.py>`
-.. _`Botan`: http://botan.randombit.net
+.. _`Botan`: https://botan.randombit.net
diff --git a/docs/development/custom-vectors/seed/generate_seed.py b/docs/development/custom-vectors/seed/generate_seed.py
index d59597fd..5c62d671 100644
--- a/docs/development/custom-vectors/seed/generate_seed.py
+++ b/docs/development/custom-vectors/seed/generate_seed.py
@@ -51,6 +51,7 @@ def write_file(data, filename):
with open(filename, "w") as f:
f.write(data)
+
OFB_PATH = "vectors/cryptography_vectors/ciphers/AES/OFB/OFBMMT128.rsp"
write_file(build_vectors(modes.OFB, OFB_PATH), "seed-ofb.txt")
CFB_PATH = "vectors/cryptography_vectors/ciphers/AES/CFB/CFB128MMT128.rsp"