Skip to content

Commit

Permalink
Add test vectors for AES-GCM-SIV
Browse files Browse the repository at this point in the history
  • Loading branch information
facutuesca committed Nov 27, 2023
1 parent 7387983 commit 0626884
Show file tree
Hide file tree
Showing 7 changed files with 1,137 additions and 0 deletions.
28 changes: 28 additions & 0 deletions docs/development/custom-vectors/aes-192-gcm-siv.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
AES-GCM-SIV vector creation
===========================

This page documents the code that was used to generate the AES-GCM-SIV test
vectors for key lengths not available in the OpenSSL test vectors. All the
vectors were generated using OpenSSL and verified with Rust.

Creation
--------

The following Python script was run to generate the vector files. The OpenSSL
test vectors were used as a base and modified to have 192-bit key length.

.. literalinclude:: /development/custom-vectors/aes-192-gcm-siv/generate_aes192gcmsiv.py

Download link: :download:`generate_aes192gcmsiv.py
</development/custom-vectors/aes-192-gcm-siv/generate_aes192gcmsiv.py>`


Verification
------------

The following Rust program was used to verify the vectors.

.. literalinclude:: /development/custom-vectors/aes-192-gcm-siv/verify-aes192gcmsiv/src/main.rs

Download link: :download:`main.rs
</development/custom-vectors/aes-192-gcm-siv/verify-aes192gcmsiv/src/main.rs>`
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# 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.

import binascii

from cryptography.hazmat.primitives.ciphers.aead import AESGCMSIV


def convert_key_to_192_bits(key: str) -> str:
"""
This takes existing 128 and 256-bit keys from test vectors from OpenSSL
and makes them 192-bit by either appending 0 or truncating the key.
"""
new_key = binascii.unhexlify(key)
if len(new_key) == 16:
new_key += b"\x00" * 8
elif len(new_key) == 32:
new_key = new_key[0:24]
else:
raise RuntimeError(
"Unexpected key length. OpenSSL AES-GCM-SIV test vectors only "
"contain 128-bit and 256-bit keys"
)

return binascii.hexlify(new_key).decode("ascii")


def encrypt(key: str, iv: str, plaintext: str, aad: str) -> (str, str):
aesgcmsiv = AESGCMSIV(binascii.unhexlify(key))
encrypted_output = aesgcmsiv.encrypt(
binascii.unhexlify(iv),
binascii.unhexlify(plaintext),
binascii.unhexlify(aad) if aad else None,
)
ciphertext, tag = encrypted_output[:-16], encrypted_output[-16:]

return (
binascii.hexlify(ciphertext).decode("ascii"),
binascii.hexlify(tag).decode("ascii"),
)


def build_vectors(filename):
count = 0
output = []
key = None
iv = None
aad = None
plaintext = None

with open(filename) as vector_file:
for line in vector_file:
line = line.strip()
if line.startswith("Key"):
if count != 0:
ciphertext, tag = encrypt(key, iv, plaintext, aad)
output.append(f"Tag = {tag}\nCiphertext = {ciphertext}\n")
output.append(f"\nCOUNT = {count}")
count += 1
aad = None
_, key = line.split(" = ")
key = convert_key_to_192_bits(key)
output.append(f"Key = {key}")
elif line.startswith("IV"):
_, iv = line.split(" = ")
output.append(f"IV = {iv}")
elif line.startswith("AAD"):
_, aad = line.split(" = ")
output.append(f"AAD = {aad}")
elif line.startswith("Plaintext"):
_, plaintext = line.split(" = ")
output.append(f"Plaintext = {plaintext}")

ciphertext, tag = encrypt(key, iv, plaintext, aad)
output.append(f"Tag = {tag}\nCiphertext = {ciphertext}\n")
return "\n".join(output)


def write_file(data, filename):
with open(filename, "w") as f:
f.write(data)


path = "vectors/cryptography_vectors/ciphers/AES/GCM-SIV/openssl.txt"
write_file(build_vectors(path), "aes-192-gcm-siv.txt")
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "verify-aes192gcmsiv"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
aes-gcm-siv = "0.11.1"
aes = "0.8.1"
hex = "0.4.3"
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use aes_gcm_siv::{
aead::{Aead, KeyInit},
AesGcmSiv, Nonce,
};

use aes::Aes192;
use aes_gcm_siv::aead::generic_array::GenericArray;
use aes_gcm_siv::aead::Payload;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;

pub type Aes192GcmSiv = AesGcmSiv<Aes192>;

struct VectorArgs {
nonce: String,
key: String,
aad: String,
tag: String,
plaintext: String,
ciphertext: String,
}

fn validate(v: &VectorArgs) {
let key_bytes = hex::decode(&v.key).unwrap();
let nonce_bytes = hex::decode(&v.nonce).unwrap();
let aad_bytes = hex::decode(&v.aad).unwrap();
let plaintext_bytes = hex::decode(&v.plaintext).unwrap();
let expected_ciphertext_bytes = hex::decode(&v.ciphertext).unwrap();
let expected_tag_bytes = hex::decode(&v.tag).unwrap();

let key_array: [u8; 24] = key_bytes.try_into().unwrap();
let cipher = Aes192GcmSiv::new(&GenericArray::from(key_array));

let payload = Payload {
msg: plaintext_bytes.as_slice(),
aad: aad_bytes.as_slice(),
};
let encrypted_bytes = cipher
.encrypt(Nonce::from_slice(nonce_bytes.as_slice()), payload)
.unwrap();
let (ciphertext_bytes, tag_bytes) = encrypted_bytes.split_at(plaintext_bytes.len());
assert_eq!(ciphertext_bytes, expected_ciphertext_bytes);
assert_eq!(tag_bytes, expected_tag_bytes);
}

fn validate_vectors(filename: &Path) {
let file = File::open(filename).expect("Failed to open file");
let reader = io::BufReader::new(file);

let mut vector: Option<VectorArgs> = None;

for line in reader.lines() {
let line = line.expect("Failed to read line");
let segments: Vec<&str> = line.splitn(2, " = ").collect();

match segments.first() {
Some(&"COUNT") => {
if let Some(v) = vector.take() {
validate(&v);
}
vector = Some(VectorArgs {
nonce: String::new(),
key: String::new(),
aad: String::new(),
tag: String::new(),
plaintext: String::new(),
ciphertext: String::new(),
});
}
Some(&"IV") => {
if let Some(v) = &mut vector {
v.nonce = segments[1].parse().expect("Failed to parse IV");
}
}
Some(&"Key") => {
if let Some(v) = &mut vector {
v.key = segments[1].to_string();
}
}
Some(&"AAD") => {
if let Some(v) = &mut vector {
v.aad = segments[1].to_string();
}
}
Some(&"Tag") => {
if let Some(v) = &mut vector {
v.tag = segments[1].to_string();
}
}
Some(&"Plaintext") => {
if let Some(v) = &mut vector {
v.plaintext = segments[1].to_string();
}
}
Some(&"Ciphertext") => {
if let Some(v) = &mut vector {
v.ciphertext = segments[1].to_string();
}
}
_ => {}
}
}

if let Some(v) = vector {
validate(&v);
}
}

fn main() {
validate_vectors(Path::new(
"vectors/cryptography_vectors/ciphers/AES/GCM-SIV/aes-192-gcm-siv.txt",
));
println!("AES-192-GCM-SIV OK.")
}
5 changes: 5 additions & 0 deletions docs/development/test-vectors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,9 @@ Symmetric ciphers

* AES (CBC, CFB, ECB, GCM, OFB, CCM) from `NIST CAVP`_.
* AES CTR from :rfc:`3686`.
* AES-GCM-SIV (KEY-LENGTH: 128, 256) from OpenSSL's `evpciph_aes_gcm_siv.txt`_.
* AES-GCM-SIV (KEY-LENGTH: 192) generated by this project.
See :doc:`/development/custom-vectors/aes-192-gcm-siv`
* AES OCB3 from :rfc:`7253`, `dkg's additional OCB3 vectors`_, and `OpenSSL's OCB vectors`_.
* AES SIV from OpenSSL's `evpciph_aes_siv.txt`_.
* 3DES (CBC, CFB, ECB, OFB) from `NIST CAVP`_.
Expand Down Expand Up @@ -992,6 +995,7 @@ Created Vectors
.. toctree::
:maxdepth: 1

custom-vectors/aes-192-gcm-siv
custom-vectors/arc4
custom-vectors/cast5
custom-vectors/chacha20
Expand Down Expand Up @@ -1055,6 +1059,7 @@ header format (substituting the correct information):
.. _`root-ed25519.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/root-ed25519.pem
.. _`server-ed25519-cert.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/server-ed25519-cert.pem
.. _`server-ed448-cert.pem`: https://github.com/openssl/openssl/blob/2a1e2fe145c6eb8e75aa2e1b3a8c3a49384b2852/test/certs/server-ed448-cert.pem
.. _`evpciph_aes_gcm_siv.txt`: https://github.com/openssl/openssl/blob/a2b1ab6100d5f0fb50b61d241471eea087415632/test/recipes/30-test_evp_data/evpciph_aes_gcm_siv.txt
.. _`evpciph_aes_siv.txt`: https://github.com/openssl/openssl/blob/d830526c711074fdcd82c70c24c31444366a1ed8/test/recipes/30-test_evp_data/evpciph_aes_siv.txt
.. _`dkg's additional OCB3 vectors`: https://gitlab.com/dkg/ocb-test-vectors
.. _`OpenSSL's OCB vectors`: https://github.com/openssl/openssl/commit/2f19ab18a29cf9c82cdd68bc8c7e5be5061b19be
Expand Down
Loading

0 comments on commit 0626884

Please sign in to comment.