Skip to content

Commit

Permalink
WIP: Add bindings for siphash-2-4 (#206)
Browse files Browse the repository at this point in the history
* Added binary bindings for SipHash-2-4

used as cypto_shorthash in libsodium

* Add python shim

* Add test for python shim.

* Make key a positional parameter.

Clarify the length must be EXACTLY equal to KEYBYTES

* Add a test for short passwords

and the requested comment about test vectors' origin.

* Try and please flake8

* Raise exception as requested in review
  • Loading branch information
lmctv authored and reaperhulk committed Dec 13, 2016
1 parent b2408a3 commit 6b1ebd8
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/bindings/crypto_shorthash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* Copyright 2013 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.
*/


// size_t crypto_hash_bytes();

size_t crypto_shorthash_siphash24_bytes();
size_t crypto_shorthash_siphash24_keybytes();

int crypto_shorthash_siphash24(unsigned char *out, const unsigned char *in,
unsigned long long inlen, const unsigned char *k);
9 changes: 9 additions & 0 deletions src/nacl/bindings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
crypto_secretbox_NONCEBYTES, crypto_secretbox_ZEROBYTES,
crypto_secretbox_open
)
from nacl.bindings.crypto_shorthash import (
BYTES as crypto_shorthash_siphash24_BYTES,
KEYBYTES as crypto_shorthash_siphash24_KEYBYTES,
crypto_shorthash_siphash24
)
from nacl.bindings.crypto_sign import (
crypto_sign, crypto_sign_BYTES, crypto_sign_PUBLICKEYBYTES,
crypto_sign_SECRETKEYBYTES, crypto_sign_SEEDBYTES,
Expand Down Expand Up @@ -77,6 +82,10 @@
"crypto_secretbox",
"crypto_secretbox_open",

"crypto_shorthash_siphash24_BYTES",
"crypto_shorthash_siphash24_KEYBYTES",
"crypto_shorthash_siphash24",

"crypto_sign_BYTES",
"crypto_sign_SEEDBYTES",
"crypto_sign_PUBLICKEYBYTES",
Expand Down
38 changes: 38 additions & 0 deletions src/nacl/bindings/crypto_shorthash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2016 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.

from __future__ import absolute_import, division, print_function

from nacl._sodium import ffi, lib

BYTES = lib.crypto_shorthash_siphash24_bytes()
KEYBYTES = lib.crypto_shorthash_siphash24_keybytes()


def crypto_shorthash_siphash24(data, key):
"""Compute a fast, cryptographic quality, keyed hash of the input data
:param data:
:type data: bytes
:param key: len(key) must be equal to
:py:data:`.KEYBYTES` (16)
:type key: bytes
"""
if len(key) != KEYBYTES:
raise ValueError("Key length must be {0} bytes".format(KEYBYTES))
digest = ffi.new("unsigned char[]", BYTES)
rc = lib.crypto_shorthash_siphash24(digest, data, len(data), key)

assert rc == 0
return ffi.buffer(digest, BYTES)[:]
136 changes: 136 additions & 0 deletions tests/test_shorthash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# Copyright 2016 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.

from __future__ import absolute_import, division, print_function

import pytest

from nacl.bindings import crypto_shorthash_siphash24

HASHES = [
b"\x31\x0e\x0e\xdd\x47\xdb\x6f\x72",
b"\xfd\x67\xdc\x93\xc5\x39\xf8\x74",
b"\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d",
b"\x2d\x7e\xfb\xd7\x96\x66\x67\x85",
b"\xb7\x87\x71\x27\xe0\x94\x27\xcf",
b"\x8d\xa6\x99\xcd\x64\x55\x76\x18",
b"\xce\xe3\xfe\x58\x6e\x46\xc9\xcb",
b"\x37\xd1\x01\x8b\xf5\x00\x02\xab",
b"\x62\x24\x93\x9a\x79\xf5\xf5\x93",
b"\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e",
b"\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a",
b"\xa7\xad\x6b\x22\x46\x2f\xb3\xf4",
b"\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75",
b"\x90\x3d\x84\xc0\x27\x56\xea\x14",
b"\xee\xf2\x7a\x8e\x90\xca\x23\xf7",
b"\xe5\x45\xbe\x49\x61\xca\x29\xa1",
b"\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f",
b"\x94\x47\xbe\x2c\xf5\xe9\x9a\x69",
b"\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b",
b"\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb",
b"\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe",
b"\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0",
b"\x88\x3e\xa3\xe3\x95\x67\x53\x93",
b"\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8",
b"\x94\xaf\x49\xf6\xc6\x50\xad\xb8",
b"\xea\xb8\x85\x8a\xde\x92\xe1\xbc",
b"\xf3\x15\xbb\x5b\xb8\x35\xd8\x17",
b"\xad\xcf\x6b\x07\x63\x61\x2e\x2f",
b"\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde",
b"\x71\x65\x95\x87\x66\x50\xa2\xa6",
b"\x28\xef\x49\x5c\x53\xa3\x87\xad",
b"\x42\xc3\x41\xd8\xfa\x92\xd8\x32",
b"\xce\x7c\xf2\x72\x2f\x51\x27\x71",
b"\xe3\x78\x59\xf9\x46\x23\xf3\xa7",
b"\x38\x12\x05\xbb\x1a\xb0\xe0\x12",
b"\xae\x97\xa1\x0f\xd4\x34\xe0\x15",
b"\xb4\xa3\x15\x08\xbe\xff\x4d\x31",
b"\x81\x39\x62\x29\xf0\x90\x79\x02",
b"\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca",
b"\x5c\x73\x33\x6a\x76\xd8\xbf\x9a",
b"\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e",
b"\x92\x59\x58\xfc\xd6\x42\x0c\xad",
b"\xa9\x15\xc2\x9b\xc8\x06\x73\x18",
b"\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4",
b"\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9",
b"\x87\x57\x75\x19\x04\x8f\x53\xa9",
b"\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb",
b"\xeb\x75\x09\x5c\xcd\x98\x6c\xd0",
b"\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6",
b"\x96\xaf\xad\xfc\x2c\xe6\x66\xc7",
b"\x72\xfe\x52\x97\x5a\x43\x64\xee",
b"\x5a\x16\x45\xb2\x76\xd5\x92\xa1",
b"\xb2\x74\xcb\x8e\xbf\x87\x87\x0a",
b"\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81",
b"\xea\xec\xb2\xa3\x0b\x22\xa8\x7f",
b"\x99\x24\xa4\x3c\xc1\x31\x57\x24",
b"\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7",
b"\x0b\x1a\x2a\x32\x65\xd5\x1a\xea",
b"\x13\x50\x79\xa3\x23\x1c\xe6\x60",
b"\x93\x2b\x28\x46\xe4\xd7\x06\x66",
b"\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c",
b"\xf3\x25\x96\x5c\xa1\x6d\x62\x9f",
b"\x57\x5f\xf2\x8e\x60\x38\x1b\xe5",
b"\x72\x45\x06\xeb\x4c\x32\x8a\x95"
]

MESG = (
b"\x00\x01\x02\x03\x04\x05\x06\x07"
b"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
b"\x10\x11\x12\x13\x14\x15\x16\x17"
b"\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
b"\x20\x21\x22\x23\x24\x25\x26\x27"
b"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
b"\x30\x31\x32\x33\x34\x35\x36\x37"
b"\x38\x39\x3a\x3b\x3c\x3d\x3e"
)

KEY = (
b"\x00\x01\x02\x03\x04\x05\x06\x07"
b"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
)


def sip24_vectors():
"""Generate test vectors using data from the reference implementation's
test defined in https://github.com/veorq/SipHash/blob/master/main.c
The key, the messages sequence and the expected hashes are all coming
from that file's definitions.
"""
vectors = []
for i, expected in enumerate(HASHES):
mesg = MESG[0:i]
vectors.append((mesg, KEY, expected))
return vectors


@pytest.mark.parametrize(("inp", "key", "expected"),
sip24_vectors()
)
def test_crypto_shorthash_siphash24(inp, key, expected):
rs = crypto_shorthash_siphash24(inp, key)
assert rs == expected


@pytest.mark.parametrize(("inp", "key", "expected"), [
(
b'\00',
b'\x00\x01\x02\x03\x04\x05\x06\x07',
b''
)
])
def test_shortened_key(inp, key, expected):
with pytest.raises(ValueError):
crypto_shorthash_siphash24(inp, key)

0 comments on commit 6b1ebd8

Please sign in to comment.