blob: 630de478b6faec8e21356852e8069a876b36fb0b [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright (C) 2017 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Outputs CSV data for NIST test cases.
Reads in a selection of test cases in NIST response file format on standard
input and outputs a CSV representation of them to standard output, with the
NIST-recommended statement in a header at the top, prefixed by #
characters. The data is in one of the following formats:
key,iv,plaintext,ciphertext
key,iv,plaintext,ciphertext,tag,aad"""
import argparse
import binascii
import sys
def dequote(value):
if value[0] == '"' and value[-1] == '"':
value = binascii.hexlify(value[1:-1])
return value
def format_records(record):
# There are a number of different input formats, depending on whether the
# particular operation includes an IV, single or multiple cipher operations,
# etc. Just check for each possibility.
if 'key' in record and 'iv' in record and 'plaintext' in record and 'ciphertext' in record:
# A normal operation with an IV
return ["{key},{iv},{plaintext},{ciphertext}".format(**record)]
elif 'key' in record and 'nonce' in record and 'plaintext' in record and 'ciphertext' in record:
# A normal operation with nonce instead of IV
return ["{key},{nonce},{plaintext},{ciphertext}".format(**record)]
elif 'key' in record and 'plaintext' in record and 'ciphertext' in record:
# A normal operation without IV
return ["{key},,{plaintext},{ciphertext}".format(**record)]
elif 'keys' in record and 'iv' in record and 'plaintext' in record and 'ciphertext' in record:
# A single triple-DES operation where all keys are the same
return ["{keys}{keys}{keys},{iv},{plaintext},{ciphertext}".format(**record)]
elif 'keys' in record and 'plaintext' in record and 'ciphertext' in record:
# A single triple-DES operation where all keys are the same without IV
return ["{keys}{keys}{keys},,{plaintext},{ciphertext}".format(**record)]
elif ('key1' in record and 'key2' in record and 'key3' in record and 'iv' in record
and 'plaintext' in record and 'ciphertext' in record):
# A single triple-DES operation with different keys for each step
return ["{key1}{key2}{key3},{iv},{plaintext},{ciphertext}".format(**record)]
elif ('key' in record and 'iv' in record and 'pt' in record and 'aad' in record
and 'ct' in record and 'tag' in record):
# An AEAD operation
return ["{key},{iv},{pt},{ct},{tag},{aad}".format(**record)]
elif ('key' in record and 'nonce' in record and 'in' in record and 'ad' in record
and 'ct' in record and 'tag' in record):
# A BoringSSL AEAD operation
return ["{key},{nonce},{in},{ct},{tag},{ad}".format(**record)]
return []
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--noheader", action='store_true')
args = parser.parse_args()
if not args.noheader:
print """# This data was developed by employees of the National Institute
# of Standards and Technology (NIST), an agency of the Federal
# Government. Pursuant to title 17 United States Code Section 105, works
# of NIST employees are not subject to copyright protection in the United
# States and are considered to be in the public domain.
#
# The data is provided by NIST as a public service and is expressly
# provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
# OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
# AND DATA ACCURACY. NIST does not warrant or make any representations
# regarding the use of the data or the results thereof, including but
# not limited to the correctness, accuracy, reliability or usefulness
# of the data. NIST SHALL NOT BE LIABLE AND YOU HEREBY RELEASE NIST FROM
# LIABILITY FOR ANY INDIRECT, CONSEQUENTIAL, SPECIAL, OR INCIDENTAL DAMAGES
# (INCLUDING DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION,
# LOSS OF BUSINESS INFORMATION, AND THE LIKE), WHETHER ARISING IN TORT,
# CONTRACT, OR OTHERWISE, ARISING FROM OR RELATING TO THE DATA (OR THE USE
# OF OR INABILITY TO USE THIS DATA), EVEN IF NIST HAS BEEN ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGES.
#
# To the extent that NIST may hold copyright in countries other than the
# United States, you are hereby granted the non-exclusive irrevocable
# and unconditional right to print, publish, prepare derivative works and
# distribute the NIST data, in any medium, or authorize others to do so
# on your behalf, on a royalty-free basis throughout the world.
#
# You may improve, modify, and create derivative works of the data or any
# portion of the data, and you may copy and distribute such modifications
# or works. Modified works should carry a notice stating that you changed
# the data and should note the date and nature of any such change. Please
# explicitly acknowledge the National Institute of Standards and Technology
# as the source of the data: Data citation recommendations are provided
# below.
#
# Permission to use this data is contingent upon your acceptance of
# the terms of this agreement and upon your providing appropriate
# acknowledgments of NIST's creation of the data.
#"""
record = {}
output_lines = []
for line in sys.stdin.readlines():
line = line.strip()
if line == '':
output_lines.extend(format_records(record))
record = {}
if ' =' in line:
record[line[:line.index('=') - 1].lower()] = line[line.index('=') + 2:]
if ': ' in line:
record[line[:line.index(':')].lower()] = dequote(line[line.index(':') + 2:])
if line == 'FAIL':
record['fail'] = True
output_lines.extend(format_records(record))
if len(output_lines) > 0:
if output_lines[0].count(',') == 3:
print """# Data is in the format:
# key,iv,plaintext,ciphertext"""
elif output_lines[0].count(',') == 5:
print """# Data is in the format:
# key,iv,plaintext,ciphertext,tag,aad"""
for output_line in output_lines:
print output_line
if __name__ == '__main__':
main()