secretstream reference vectors¶
Since libsodium’s tests do not provide reference data for the secretstream
construction, the implementation is verified with a
secretstream_test_vector
utility program that produces custom test vectors
by making specific calls to the libsodium API.
To build the secretstream_test_vector
you need a C
language compiler,
a prebuilt libsodium library more recent than version 1.0.14 and the
corresponding include headers.
In a UNIX-like programming environment you should then execute:
$ cc -o secretstream_test_vector secretstream_test_vector.c -lsodium -lc
If you prefer using a locally compiled installation of the bundled sources, refer to Building the bundled library and then run:
$ cc -o secretstream_test_vector secretstream_test_vector.c \
${SODIUMINCL} ${SODIUMLIB} -lsodium -lc
Vector generation¶
$ ./secretstream_test_vector -h
Usage: secretstream_test_vector [-c num_chunks] [-r]
When called, the program will output a JSON dictionary containing
key
, header
, and chunks
. The chunks
is a list of individual
messages passed to crypto_secretstream_xchacha20poly1305_push
containing
tag
, message
, ad
and ciphertext
keys.
Source code for the vector checker utility¶
The source code for secretstream_test_vector
is available inside
the docs/vectors/c-source
directory of PyNaCl distribution
and can also be directly downloaded from
secretstream_test_vector.c
.
/*
* Copyright 2018 Donald Stufft and individual contributors
*
* 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.
*
* Test vector generator/checker for libsodium's crypto_secretstream APIs
* to build in a unix-like environment, use a command line like
* $ cc secretstream_test_vector.c \
* -I${IPATH} -L${LPATH} -lsodium \
* -o secretstream_test_vector
* with IPATH and LPATH defined to respectively point to libsodium's include path
* and to the directory containing the link library libsodium.a or libsodium.o
*
*/
#include <stdio.h>
#include <string.h>
#include <sodium.h>
#include <unistd.h>
#define MAX_AD_SIZE 32
#define MAX_CHUNK_SIZE 512
#define CHK(cmd) \
do { if ((rc = (cmd)) != 0) { \
fprintf(stderr, "api call failed, code=%d", rc); \
exit(1); \
}} while(0)
int usage(int argc, char **argv) {
fprintf(stderr, "Usage: %s [-c num_chunks] [-r]\n", argv[0]);
return 1;
}
int main (int argc, char **argv) {
int c, rc;
int num_chunks = 1;
int rekey = 0;
crypto_secretstream_xchacha20poly1305_state state;
unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES];
unsigned char key[crypto_secretstream_xchacha20poly1305_KEYBYTES];
unsigned char m[MAX_CHUNK_SIZE];
unsigned char ad[MAX_AD_SIZE];
unsigned char ct[MAX_CHUNK_SIZE + crypto_secretstream_xchacha20poly1305_ABYTES];
char key_hex[sizeof(key) * 2 + 1];
char header_hex[sizeof(header) * 2 + 1];
char m_hex[sizeof(m) * 2 + 1];
char ad_hex[sizeof(ad) * 2 + 1];
char ct_hex[sizeof(ct) * 2 + 1];
unsigned long long m_len, ad_len, ct_len;
unsigned char tag;
while ((c = getopt(argc, argv, "hc:r")) != -1) {
switch (c) {
case 'c':
num_chunks = atoi(optarg);
break;
case 'r':
rekey = 1;
break;
case 'h':
return usage(argc, argv);
default:
return 1;
}
}
if (optind < argc) return usage(argc, argv);
if (sodium_init() == -1) {
exit(1);
}
/* output format:
* {
* "key": "hex",
* "header": "hex",
* "chunks": [
* {
* "tag": 0,
* "ad": "hex",
* "message": "hex",
* "ciphertext": "hex"
* },
* ...
* ]
* }
*/
crypto_secretstream_xchacha20poly1305_keygen(key);
CHK(crypto_secretstream_xchacha20poly1305_init_push(&state, header, key));
sodium_bin2hex(key_hex, sizeof key_hex, key, sizeof key);
sodium_bin2hex(header_hex, sizeof header_hex, header, sizeof header);
printf("{\n \"key\": \"%s\",\n \"header\": \"%s\",\n \"chunks\": [\n",
key_hex, header_hex);
for (c = 1 ; c <= num_chunks ; ++c) {
tag =
c == num_chunks ? crypto_secretstream_xchacha20poly1305_TAG_FINAL
: rekey ? crypto_secretstream_xchacha20poly1305_TAG_REKEY
: crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
ad_len = randombytes_uniform(MAX_AD_SIZE);
m_len = randombytes_uniform(MAX_CHUNK_SIZE - 1) + 1;
randombytes_buf(m, m_len);
randombytes_buf(ad, ad_len);
CHK(crypto_secretstream_xchacha20poly1305_push(
&state, ct, &ct_len, m, m_len, ad, ad_len, tag));
sodium_bin2hex(m_hex, m_len * 2 + 1, m, m_len);
if (ad_len > 0) {
sodium_bin2hex(ad_hex, ad_len * 2 + 1, ad, ad_len);
}
sodium_bin2hex(ct_hex, ct_len * 2 + 1, ct, ct_len);
printf(" {\n"
" \"tag\": %d,\n \"ad\": %s%s%s,\n"
" \"message\": \"%s\",\n \"ciphertext\": \"%s\"\n"
" }%s\n",
tag,
ad_len > 0 ? "\"" : "",
ad_len > 0 ? ad_hex : "null",
ad_len > 0 ? "\"" : "",
m_hex,
ct_hex,
c < num_chunks ? "," : "");
}
printf(" ]\n}\n");
return 0;
}