├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── main.cpp ├── src ├── siphash.cpp └── siphash.h └── test └── test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | ### C ### 2 | # Object files 3 | *.o 4 | *.ko 5 | *.obj 6 | *.elf 7 | 8 | # Precompiled Headers 9 | *.gch 10 | *.pch 11 | 12 | # Libraries 13 | *.lib 14 | *.a 15 | *.la 16 | *.lo 17 | 18 | # Shared objects (inc. Windows DLLs) 19 | *.dll 20 | *.so 21 | *.so.* 22 | *.dylib 23 | 24 | # Executables 25 | *.exe 26 | *.out 27 | *.app 28 | *.i*86 29 | *.x86_64 30 | *.hex 31 | 32 | # Debug files 33 | *.dSYM/ 34 | 35 | # Build files 36 | build/* 37 | 38 | # IDE files 39 | .idea/ 40 | CMakeLists.txt -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | os: 3 | - linux 4 | - osx 5 | compiler: 6 | - clang 7 | - gcc 8 | before_script: make siphash_test 9 | script: ./build/test/siphash_test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Isaac Whitfield 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | B = build 2 | BT = $(B)/test 3 | CFLAGS = -g -O3 -ansi -pedantic -Wall -Wextra -std=c++03 4 | PREFIX ?= /usr/local 5 | SRC = main.cpp src/siphash.cpp 6 | TARGET ?= $(PREFIX)/bin 7 | TEST = test/test.cpp src/siphash.cpp 8 | 9 | all: siphash 10 | siphash: $(SRC) 11 | mkdir -p $(B) 12 | $(CXX) $(CFLAGS) $^ -o $(B)/$@ 13 | clean: 14 | $(RM) -r $(B) 15 | install: siphash 16 | mkdir -p $(TARGET) 17 | cp -f $(B)/siphash $(TARGET)/siphash 18 | siphash_test: $(TEST) 19 | mkdir -p $(BT) 20 | $(CXX) $^ $(CFLAGS) -o $(BT)/siphash_test 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SipHash 2 | 3 | [![Build Status](https://travis-ci.org/zackehh/siphash-cpp.svg?branch=master)](https://travis-ci.org/zackehh/siphash-cpp) 4 | 5 | A C++ implementation of the SipHash cryptographic hash family. Supports any variation, although defaults to the widely used SipHash-2-4. 6 | 7 | This library was heavily influenced by [veorq's C implementation](https://github.com/veorq/siphash), but modified to be made a little more user-friendly (IMO). The intention is to pick this over into a Node lib for faster execution. 8 | 9 | ## Usage 10 | 11 | You can use this library as either an extension of your own project, or via the command line using a wrapper. 12 | 13 | ### Command Line Setup 14 | 15 | You have to build manually if you want to create the command line interface: 16 | 17 | ```bash 18 | $ cd /tmp 19 | $ git clone https://github.com/zackehh/siphash-cpp.git 20 | $ cd siphash-cpp 21 | $ make install 22 | ``` 23 | 24 | From there you can access `siphash` through your terminal, as follows: 25 | 26 | ```bash 27 | $ siphash -k "0123456789ABCDEF" -i "hello" -c 2 -d 4 -b 10 28 | ``` 29 | 30 | The applicable options exist of: 31 | 32 | - `-k` - the key to use for the hash (required) 33 | - `-i` - the input string to hash (required) 34 | - `-f` - a file path to hash 35 | - `-c` - the rounds of C compression (defaults to c) 36 | - `-d` - the rounds of D compression (defaults to 4) 37 | - `-b` - the base print the hash in (defaults to 10) 38 | 39 | Note: 40 | 41 | - `-k` must be provided, along with either of `-i` or `-f`. 42 | - `-b` accepts `8`, `10` or `16`. Any other value will be treated as default. 43 | - Be careful when using `-f`, as the file input is buffered into memory. 44 | - Avoid adventurous use cases, this is a tool designed for debugging rather than heavy use. 45 | 46 | ## Testing 47 | 48 | The tests are very barebones at the moment, but you can run them as follows: 49 | 50 | ```c 51 | $ make siphash_test 52 | $ ./build/test/siphash_test 53 | ``` 54 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef _WIN32 10 | #include 11 | #else 12 | #include 13 | #endif 14 | 15 | #include "src/siphash.h" 16 | 17 | using namespace std; 18 | 19 | int show_help() { 20 | printf("Usage: siphash -k [-i | -f ] [-b=10] [-c=2] [-d=4]\n"); 21 | return 1; 22 | } 23 | 24 | int main(int argc, char *argv[]) { 25 | int dc = fileno(stdin); 26 | 27 | #ifdef _WIN32 28 | bool tty = _isatty(dc); 29 | #else 30 | bool tty = isatty(dc); 31 | #endif 32 | 33 | char* key = NULL; 34 | char* input = NULL; 35 | char* fname = NULL; 36 | 37 | int b = 10, c = 0, d = 0, option = 0; 38 | 39 | if (argc < 2) { 40 | return show_help(); 41 | } 42 | 43 | while ((option = getopt(argc, argv, "f:k:i:c:d:b:")) != -1) { 44 | switch (option) { 45 | case 'b': 46 | b = atoi(optarg); 47 | break; 48 | case 'c': 49 | c = atoi(optarg); 50 | break; 51 | case 'd': 52 | d = atoi(optarg); 53 | break; 54 | case 'f': 55 | if (access(optarg, F_OK) == -1) { 56 | break; 57 | } 58 | fname = optarg; 59 | break; 60 | case 'i': 61 | input = optarg; 62 | break; 63 | case 'k': 64 | key = optarg; 65 | break; 66 | } 67 | } 68 | 69 | if (key == NULL || (tty && input == NULL && fname == NULL)) { 70 | return show_help(); 71 | } 72 | 73 | if (strlen(key) != 16) { 74 | printf("Key must consist of exactly 16 bytes!\n"); 75 | return 1; 76 | } 77 | 78 | if (c <= 0) { 79 | c = 2; 80 | } 81 | 82 | if (d <= 0) { 83 | d = 4; 84 | } 85 | 86 | SipHash sip(key, c, d); 87 | 88 | if (!tty) { 89 | char *chunk = new char[8192]; 90 | 91 | while (!cin.eof()) { 92 | cin.read(chunk, 8192); 93 | 94 | for(int i = 0; i < cin.gcount(); i++){ 95 | sip.update(chunk[i]); 96 | } 97 | } 98 | } 99 | else if (fname != NULL) { 100 | struct stat filestatus; 101 | stat(fname, &filestatus); 102 | 103 | size_t total_size = filestatus.st_size; 104 | size_t chunk_size = 16; 105 | 106 | size_t total_chunks = total_size / chunk_size; 107 | size_t last_chunk_size = total_size % chunk_size; 108 | 109 | if (last_chunk_size != 0) { 110 | ++total_chunks; 111 | } else { 112 | last_chunk_size = chunk_size; 113 | } 114 | 115 | ifstream file(fname, ifstream::binary); 116 | 117 | for (size_t chunk = 0; chunk < total_chunks; ++chunk) { 118 | size_t this_chunk_size = chunk == total_chunks - 1 119 | ? last_chunk_size 120 | : chunk_size; 121 | 122 | vector chunk_data(this_chunk_size); 123 | file.read(&chunk_data[0], this_chunk_size); 124 | 125 | for (size_t i = 0; i < this_chunk_size; i++) { 126 | sip.update(chunk_data[i]); 127 | } 128 | } 129 | } 130 | else { 131 | sip.update(input); 132 | } 133 | 134 | cout << setbase(b); 135 | cout << sip.digest() << endl; 136 | 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /src/siphash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "siphash.h" 3 | 4 | #define ROTATE_LEFT(x, b) (unsigned long)(((x) << (b)) | ((x) >> (64 - (b)))) 5 | 6 | #define COMPRESS \ 7 | v0 += v1; \ 8 | v2 += v3; \ 9 | v1 = ROTATE_LEFT(v1, 13); \ 10 | v3 = ROTATE_LEFT(v3, 16); \ 11 | v1 ^= v0; \ 12 | v3 ^= v2; \ 13 | v0 = ROTATE_LEFT(v0, 32); \ 14 | v2 += v1; \ 15 | v0 += v3; \ 16 | v1 = ROTATE_LEFT(v1, 17); \ 17 | v3 = ROTATE_LEFT(v3, 21); \ 18 | v1 ^= v2; \ 19 | v3 ^= v0; \ 20 | v2 = ROTATE_LEFT(v2, 32); 21 | 22 | #define DIGEST_BLOCK \ 23 | v3 ^= m; \ 24 | do { \ 25 | int i; \ 26 | for(i = 0; i < c; i++){ \ 27 | COMPRESS \ 28 | } \ 29 | } while (0); \ 30 | v0 ^= m; 31 | 32 | #define U8TO64_LE(p) \ 33 | (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ 34 | ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ 35 | ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ 36 | ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) 37 | 38 | SipHash::SipHash(char key[16], int c, int d) { 39 | this->c = c; 40 | this->d = d; 41 | 42 | uint64_t k0 = U8TO64_LE(key); 43 | uint64_t k1 = U8TO64_LE(key + 8); 44 | 45 | this->v0 = (0x736f6d6570736575 ^ k0); 46 | this->v1 = (0x646f72616e646f6d ^ k1); 47 | this->v2 = (0x6c7967656e657261 ^ k0); 48 | this->v3 = (0x7465646279746573 ^ k1); 49 | 50 | this->m_idx = 0; 51 | this->input_len = 0; 52 | this->m = 0; 53 | } 54 | 55 | SipHash::~SipHash() { 56 | // TODO Auto-generated destructor stub 57 | } 58 | 59 | SipHash* SipHash::update(char b) { 60 | input_len++; 61 | m |= (((long) b & 0xff) << (m_idx++ * 8)); 62 | if (m_idx >= 8) { 63 | DIGEST_BLOCK 64 | m_idx = 0; 65 | m = 0; 66 | } 67 | return this; 68 | } 69 | 70 | SipHash* SipHash::update(char data[]) { 71 | const char *pszChar = data; 72 | while (pszChar != NULL && *pszChar != '\0') { 73 | update(*pszChar); 74 | pszChar++; 75 | } 76 | return this; 77 | } 78 | 79 | uint64_t SipHash::digest() { 80 | while (m_idx < 7) { 81 | m |= 0 << (m_idx++ * 8); 82 | } 83 | 84 | m |= ((uint64_t) input_len) << (m_idx * 8); 85 | 86 | DIGEST_BLOCK 87 | 88 | v2 ^= 0xff; 89 | 90 | for(int i = 0; i < d; i++){ 91 | COMPRESS 92 | } 93 | 94 | return ((uint64_t) v0 ^ v1 ^ v2 ^ v3); 95 | } 96 | -------------------------------------------------------------------------------- /src/siphash.h: -------------------------------------------------------------------------------- 1 | #ifndef SIPHASH_NODE_SIPHASH_H 2 | #define SIPHASH_NODE_SIPHASH_H 3 | 4 | #include 5 | 6 | class SipHash { 7 | private: 8 | int c, d, m_idx; 9 | uint64_t v0, v1, v2, v3, m; 10 | unsigned char input_len; 11 | public: 12 | SipHash(char key[16], int c = 2, int d = 4); 13 | ~SipHash(); 14 | SipHash* update(char data); 15 | SipHash* update(char data[]); 16 | uint64_t digest(); 17 | }; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "../src/siphash.h" 6 | 7 | void test(uint64_t expected, char key[16], char input[], int c, int d) { 8 | SipHash sipHash(key, c, d); 9 | 10 | sipHash.update(input); 11 | 12 | assert(expected == sipHash.digest()); 13 | } 14 | 15 | int main () { 16 | test(4402678656023170274, (char *) "0123456789ABCDEF", (char *) "hello", 2, 4); /* test default hash */ 17 | test(4402678656023170274, (char *) "0123456789ABCDEFF", (char *) "hello", 2, 4); /* extra byte ignored */ 18 | test(14986662229302055855UL, (char *) "0123456789ABCDEF", (char *) "hello", 4, 8); /* check compression changes */ 19 | return 0; 20 | } 21 | --------------------------------------------------------------------------------