├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile.am ├── README.md ├── configure.ac ├── examples ├── Makefile.am └── example1.c ├── src ├── Makefile.am ├── shick_crypto.c └── shick_crypto.h └── tests ├── Makefile.am ├── acceptancetests.c ├── gcov └── unittests.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | 5 | # Libraries 6 | *.lib 7 | *.a 8 | 9 | # Shared objects (inc. Windows DLLs) 10 | *.dll 11 | *.so 12 | *.so.* 13 | *.dylib 14 | 15 | # Executables 16 | *.exe 17 | *.out 18 | *.app 19 | 20 | # autoconf and automake 21 | Makefile 22 | Makefile.in 23 | aclocal.m4 24 | autom4te.cache/ 25 | build-aux/ 26 | config.h 27 | config.h.in 28 | config.log 29 | config.status 30 | configure 31 | libtool 32 | src/.deps/ 33 | src/.libs/ 34 | src/Makefile 35 | src/Makefile.in 36 | src/libshickcrypto.la 37 | src/main 38 | src/shick_crypto.lo 39 | stamp-h1 40 | tests/.deps/ 41 | tests/Makefile 42 | tests/Makefile.in 43 | tests/.libs/ 44 | tests/test-suite.log 45 | acceptancetests 46 | acceptancetests.log 47 | acceptancetests.trs 48 | unittests 49 | unittests.log 50 | unittests.trs 51 | 52 | # Gcov 53 | *.gcda 54 | *.gcno 55 | *.gcov 56 | tests/gcov.log 57 | tests/gcov.trs 58 | 59 | # Examples 60 | examples/.deps/ 61 | examples/.libs/ 62 | examples/example1 63 | 64 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | notifications: 3 | email: 4 | - travis-ci@pustina.net 5 | install: 6 | - sudo apt-get install -y check git 7 | - OLD_PWD=`pwd`; cd /tmp; git clone https://github.com/jedisct1/libsodium.git; cd libsodium; autoreconf --install && ./configure --prefix=/usr && make && sudo make install; cd $OLD_PWD 8 | script: autoreconf --install && ./configure && make && make check 9 | compiler: 10 | - clang 11 | - gcc 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, lukaspustina 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | * Neither the name of the {organization} nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src . tests examples 2 | 3 | MOSTLYCLEANFILES = *.gcda *.gcno *.gcov tests/gcov.log tests/gcov.trs tests/*.xml 4 | 5 | if COND_GCOV 6 | MAYBE_COVERAGE=-fprofile-arcs -ftest-coverage 7 | endif 8 | 9 | AM_CFLAGS := $(MAYBE_COVERAGE) $(AM_CFLAGS) 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shick Crypto Library 2 | This library shows how to use [NaCl][NaCl] in form of [libsodium][libsodium] to securely encrypt a message with asymmetric encryption. 3 | 4 | In German, *Schick!* (pronounced [shick]) means *Send!*. So, clone and start sending securely. You can find Shick Crypto Library 5 | 6 | * on [GitHub](https://github.com/lukaspustina/shick_crypto) 7 | * on [Travis CI](https://travis-ci.org/lukaspustina/shick_crypto) 8 | 9 | Please feel free to clone and adapt to your needs. If you find any bugs or have enhancements, please share it. I will react on pull requests promptly. 10 | 11 | ## How Does it Work 12 | 13 | Shick Crypto Library is just a thin wrapper around libsodium. The main functionality consists of two functions, i.e., `shick_crypto_enc_message` and `shick_crypto_dec_message`. Messages are encrypted and decrypted following the same pattern as used in [GPG](http://en.wikipedia.org/wiki/GNU_Privacy_Guard#Process) by generating a random *symmetric* key, encrypting a message symmetrically, and finally encrypt the random key *asymmetrically*. Since asymmetric encryption is computational more expensive than symmetric encryption, this pattern combines the security and speed of both worlds. In addition, all encryption, i.e., asymmetric and symmetric encryption, is protected by [MACs](http://en.wikipedia.org/wiki/Message_authentication_code) and initialized with [nouces](http://en.wikipedia.org/wiki/Cryptographic_nonce). The concrete algorithms used by NaCl are currently [Curve25519](http://en.wikipedia.org/wiki/Curve25519) elliptic curve cryptography for asymmetric encryption, [Salsa20](http://en.wikipedia.org/wiki/Salsa20) for symmetric encryption, and [Poly1305-AES](http://en.wikipedia.org/wiki/Poly1305-AES) for [message authentication code](http://en.wikipedia.org/wiki/Message_authentication_code) (MAC) computation. 14 | 15 | ## How to Use 16 | 17 | ### Prerequisites 18 | 19 | 1. Crypto library [NaCl][NaCl] in form of [libsodium][libsodium] 20 | 2. C unit testing library [Check](http://en.wikipedia.org/wiki/Cryptographic_nonce) 21 | 22 | Check is usually available on all Linux distributions and in [Homebrew](http://en.wikipedia.org/wiki/Cryptographic_nonce). libsodium might be available, but please make sure you use a recent version. It is easy to install from source -- see their [Readme](https://github.com/jedisct1/libsodium/blob/master/README.markdown). If you compile from source, please make sure to pass the parameter `--enable-blocking-random` to `./configure` in order to use `/dev/random` for random number generation. 23 | 24 | [NaCl]:http://nacl.cace-project.eu 25 | [libsodium]:https://github.com/jedisct1/libsodium 26 | 27 | ### Compile 28 | 29 | 1. `autoreconf --install && ./configure && make` 30 | 31 | ### Run Tests 32 | 33 | 1. `make check` for acceptance and unit tests 34 | 1. `./configure --enable-gcov && make clean && make && make check` for coverage test 35 | 36 | ### API 37 | 38 | Shick Crypto Library has six functions: 39 | 40 | ``` 41 | // Returns Shick Crypto Library version 42 | const char* shick_crypto_version() 43 | ``` 44 | ``` 45 | // Initializes libsodium and should be run once per application run 46 | void shick_crypto_init() 47 | ``` 48 | ``` 49 | // Creates an asymmetric key pair 50 | int shick_crypto_create_asymmetric_key_pair(secret_key, public_key) 51 | ``` 52 | ``` 53 | // Creates a random nonce of specific length 54 | void shick_create_nonce(nonce, len) 55 | ``` 56 | ``` 57 | // Encrypts a message with a random symmetric key and encrypts this key asymmetrically for all recipients 58 | int shick_crypto_enc_message(sender_secret_key, recipient_public_keys, 59 | amount_of_recipients, message, message_len, nonce, encrypted_symmetric_keys, ciphertext) 60 | ``` 61 | ``` 62 | // Decrypts a message with a asymmetrically encrypted symmetric key 63 | int shick_crypto_dec_message(recipient_secret_key, sender_public_key, 64 | encrypted_symmetric_key, ciphertext, cipertext_len, nonce, message) 65 | ``` 66 | 67 | The results to send to each recipient are the chosen nonce, the encrypted symmetric key for the particular recipient, and the ciphertext. 68 | 69 | ### Example 70 | 71 | This example is an excerpt from the example in [examples/examples1.c](https://github.com/lukaspustina/shick_crypto/blob/master/examples/example1.c). See there for a full example. 72 | 73 | ``` 74 | SC_CHAR message[] = "Shick Crypto Lib"; // Message to send 75 | 76 | int amount_of_recipients = 1; // Number of recipients 77 | const SC_CHAR* recipient_public_keys[amount_of_recipients]; // List of recipients 78 | 79 | // Buffer Alice' and Bob's key pairs 80 | SC_CHAR alice_secret_key[crypto_box_SECRETKEYBYTES]; 81 | SC_CHAR alice_public_key[crypto_box_PUBLICKEYBYTES]; 82 | SC_CHAR bob_secret_key[crypto_box_SECRETKEYBYTES]; 83 | SC_CHAR bob_public_key[crypto_box_PUBLICKEYBYTES]; 84 | 85 | // Buffers for nonce, ciphertext, and encrypted symmetric keys 86 | SC_CHAR nonce[crypto_box_NONCEBYTES]; 87 | SC_CHAR ciphertext[crypto_box_MACBYTES + sizeof message]; // Space for MAC 88 | SC_ENC_SYM_KEY encrypted_symmetric_keys[amount_of_recipients]; 89 | 90 | SC_CHAR message_decrypted[sizeof message]; // Buffer for roundtrip decrypted message 91 | 92 | shick_crypto_init(); // Init libsodium 93 | 94 | // Create Alice' and Bob's key pairs 95 | shick_crypto_create_asymmetric_key_pair(alice_secret_key, alice_public_key); 96 | shick_crypto_create_asymmetric_key_pair(bob_secret_key, bob_public_key); 97 | recipient_public_keys[0] = bob_public_key; 98 | 99 | shick_create_nonce(nonce, sizeof nonce); // Create nonce for asymmetric encryption 100 | 101 | // Encrypt and sign from Alice to Bob 102 | shick_crypto_enc_message(alice_secret_key, recipient_public_keys, 103 | amount_of_recipients, message, sizeof message, nonce, encrypted_symmetric_keys, ciphertext); 104 | // Now your message is encrypted for Bob and Bobby 105 | // Send (nonce, encrypted_symmetric_keys[i], ciphertext) to Bob and Bobby 106 | 107 | // Decrypt and verify signature for Bob from Alice 108 | shick_crypto_dec_message(bob_secret_key, alice_public_key, 109 | encrypted_symmetric_keys[0], ciphertext, sizeof ciphertext, nonce, message_decrypted); 110 | ``` 111 | 112 | Send securely. 113 | 114 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.59]) 2 | AC_INIT([shick_crypto], [0.1], [lukas AT shickapp.com]) 3 | 4 | AC_CONFIG_SRCDIR([src/shick_crypto.c]) 5 | AC_CONFIG_AUX_DIR([build-aux]) 6 | AM_INIT_AUTOMAKE([-Werror foreign 1.9.6]) 7 | 8 | AC_PROG_CC 9 | AC_PROG_CC_STDC 10 | AM_PROG_AR 11 | AC_PROG_LIBTOOL 12 | 13 | AM_PATH_CHECK() 14 | AC_SEARCH_LIBS(sodium_init, [sodium], [ ], AC_ERROR([libsodium not found])) 15 | 16 | AC_ARG_ENABLE([gcov], 17 | [AS_HELP_STRING([--enable-gcov], 18 | [use Gcov to test the test suite])], 19 | [], 20 | [enable_gcov=no]) 21 | AM_CONDITIONAL([COND_GCOV],[test '!' "$enable_gcov" = no]) 22 | 23 | AC_HEADER_STDC 24 | AC_CHECK_HEADERS([stdlib.h]) 25 | 26 | AC_FUNC_MALLOC 27 | 28 | AC_CONFIG_HEADERS([config.h]) 29 | 30 | AC_CONFIG_FILES([Makefile 31 | src/Makefile 32 | tests/Makefile 33 | examples/Makefile]) 34 | 35 | AC_OUTPUT 36 | 37 | -------------------------------------------------------------------------------- /examples/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = example1 2 | 3 | example1_SOURCES = example1.c $(top_builddir)/src/shick_crypto.h 4 | example1_LDADD = $(top_builddir)/src/libshickcrypto.la 5 | 6 | -------------------------------------------------------------------------------- /examples/example1.c: -------------------------------------------------------------------------------- 1 | #include "../src/shick_crypto.h" 2 | 3 | void printBufferAsHex(SC_CHAR* buffer, SC_LEN buffer_len) { 4 | for (int c=0; c < buffer_len; c++) { 5 | printf(",0x%02x",(unsigned int) buffer[c]); 6 | if (c % 8 == 7) printf("\n"); 7 | } 8 | } 9 | 10 | int run_example() { 11 | SC_CHAR message[] = "Shick Crypto Lib"; 12 | 13 | int result = 0; 14 | int amount_of_recipients = 1; 15 | 16 | SC_CHAR alice_secret_key[crypto_box_SECRETKEYBYTES]; 17 | SC_CHAR alice_public_key[crypto_box_PUBLICKEYBYTES]; 18 | SC_CHAR bob_secret_key[crypto_box_SECRETKEYBYTES]; 19 | SC_CHAR bob_public_key[crypto_box_PUBLICKEYBYTES]; 20 | 21 | const SC_CHAR* recipient_public_keys[amount_of_recipients]; 22 | SC_CHAR nonce[crypto_box_NONCEBYTES]; 23 | SC_CHAR ciphertext[crypto_box_MACBYTES + sizeof message]; 24 | SC_ENC_SYM_KEY encrypted_symmetric_keys[amount_of_recipients]; 25 | SC_CHAR message_decrypted[sizeof message]; 26 | 27 | shick_crypto_init(); 28 | 29 | shick_crypto_create_asymmetric_key_pair(alice_secret_key, alice_public_key); 30 | shick_crypto_create_asymmetric_key_pair(bob_secret_key, bob_public_key); 31 | 32 | recipient_public_keys[0] = bob_public_key; 33 | 34 | shick_create_nonce(nonce, sizeof nonce); 35 | 36 | // Encrypt 37 | shick_crypto_enc_message(alice_secret_key, recipient_public_keys, amount_of_recipients, message, sizeof message, nonce, encrypted_symmetric_keys, ciphertext); 38 | // Now your message is encrypted for Bob and Bobby 39 | // Send (nonce, encrypted_symmetric_keys[i], ciphertext) to Bob and Bobby 40 | 41 | // Decrypt for Bob 42 | shick_crypto_dec_message(bob_secret_key, alice_public_key, encrypted_symmetric_keys[0], ciphertext, sizeof ciphertext, nonce, message_decrypted); 43 | 44 | 45 | // Show data on console 46 | printf("* Alice' SK:\n"); printBufferAsHex(alice_secret_key, crypto_box_SECRETKEYBYTES); 47 | printf("* Alice' PK:\n"); printBufferAsHex(alice_public_key, crypto_box_PUBLICKEYBYTES); 48 | printf("* Bobs SK:\n"); printBufferAsHex(bob_secret_key, crypto_box_SECRETKEYBYTES); 49 | printf("* Bobs PK:\n"); printBufferAsHex(bob_public_key, crypto_box_PUBLICKEYBYTES); 50 | printf("* Nonce:\n"); printBufferAsHex(nonce, crypto_box_NONCEBYTES); 51 | SC_ENC_SYM_KEY key = encrypted_symmetric_keys[0]; 52 | printf("* Enc Sym Key:\n"); printBufferAsHex(((SC_CHAR*) &key), sizeof(SC_ENC_SYM_KEY)); 53 | printf("* Cipher Text:\n"); printBufferAsHex(ciphertext, sizeof ciphertext); 54 | 55 | return 0; 56 | } 57 | 58 | int main() { 59 | return run_example(); 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libshickcrypto.la 2 | libshickcrypto_la_SOURCES = shick_crypto.c shick_crypto.h 3 | 4 | -------------------------------------------------------------------------------- /src/shick_crypto.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "shick_crypto.h" 7 | 8 | const char* 9 | shick_crypto_version() { 10 | return PACKAGE_VERSION; 11 | } 12 | 13 | /* 14 | * Recommended to call in order to select optimal implementation details 15 | * at run time. 16 | * See https://github.com/jedisct1/libsodium/blob/master/README.markdown 17 | */ 18 | void 19 | shick_crypto_init() { 20 | sodium_init(); 21 | } 22 | 23 | int 24 | shick_crypto_create_asymmetric_key_pair(SC_CHAR secret_key[crypto_box_SECRETKEYBYTES], 25 | SC_CHAR public_key[crypto_box_PUBLICKEYBYTES]) { 26 | return crypto_box_keypair(public_key, secret_key); 27 | } 28 | 29 | void 30 | shick_create_nonce(SC_CHAR* nonce, int len) { 31 | randombytes_buf(nonce, len); 32 | } 33 | 34 | int 35 | shick_crypto_enc_message(const SC_CHAR sender_secret_key[crypto_box_SECRETKEYBYTES], 36 | const SC_CHAR** recipient_public_keys, 37 | const int amount_of_recipients, 38 | const SC_CHAR* message, 39 | const SC_LEN message_len, 40 | SC_CHAR nonce[crypto_box_NONCEBYTES], 41 | SC_ENC_SYM_KEY* encrypted_symmetric_keys, 42 | SC_CHAR* ciphertext) { 43 | int failed = 0; 44 | 45 | // Create symmetric key 46 | SC_SYM_KEY sym_key; 47 | randombytes_buf((void*) sym_key.key, sizeof sym_key.key); 48 | randombytes_buf((void*) sym_key.nonce, sizeof sym_key.nonce); 49 | 50 | // Encrypt message symmetrically 51 | failed = crypto_secretbox_easy(ciphertext, message, message_len, sym_key.nonce, sym_key.key); 52 | if (failed) return SC_ENC_SYM_FAILED; 53 | 54 | // Encrypt symmetric key asymmetrically for each recipient 55 | for (int i = 0; i < amount_of_recipients; i++) { 56 | SC_CHAR public_key[crypto_box_PUBLICKEYBYTES]; 57 | memcpy(public_key, recipient_public_keys[i], crypto_box_PUBLICKEYBYTES); 58 | failed = crypto_box_easy((SC_CHAR*) &encrypted_symmetric_keys[i], (SC_CHAR*) &sym_key, sizeof sym_key, nonce, public_key, sender_secret_key); 59 | if (failed) return SC_ENC_ASYM_FAILED; 60 | } 61 | 62 | return 0; 63 | } 64 | 65 | int 66 | shick_crypto_dec_message(const SC_CHAR recipient_secret_key[crypto_box_SECRETKEYBYTES], 67 | const SC_CHAR sender_public_key[crypto_box_PUBLICKEYBYTES], 68 | const SC_ENC_SYM_KEY encrypted_symmetric_key, 69 | const SC_CHAR* ciphertext, 70 | const SC_LEN ciphertext_len, 71 | const SC_CHAR nonce[crypto_box_NONCEBYTES], 72 | SC_CHAR* message) { 73 | int failed = 0; 74 | SC_CHAR buffer[sizeof(SC_SYM_KEY)]; 75 | SC_SYM_KEY* sym_key; 76 | 77 | // Decrypt symmetric key 78 | failed = crypto_box_open_easy(buffer, (SC_CHAR*) &encrypted_symmetric_key, sizeof encrypted_symmetric_key, nonce, sender_public_key, recipient_secret_key); 79 | if (failed) return SC_DEC_ASYM_FAILED; 80 | 81 | // Decrypt message with symmetric key 82 | sym_key = (SC_SYM_KEY*) buffer; 83 | failed = crypto_secretbox_open_easy(message, ciphertext, ciphertext_len, sym_key->nonce, sym_key->key); 84 | if (failed) return SC_DEC_SYM_FAILED; 85 | 86 | return 0; 87 | } 88 | 89 | -------------------------------------------------------------------------------- /src/shick_crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef SHICK_CRYPTO 2 | #define SHICK_CRYPTO 3 | 4 | #include 5 | 6 | const int SC_ENC_ASYM_FAILED = -1001; 7 | const int SC_ENC_SYM_FAILED = -1002; 8 | const int SC_DEC_ASYM_FAILED = -1101; 9 | const int SC_DEC_SYM_FAILED = -1102; 10 | 11 | 12 | typedef unsigned char SC_CHAR; 13 | typedef unsigned long long SC_LEN; 14 | typedef struct { 15 | SC_CHAR key[crypto_secretbox_KEYBYTES]; 16 | SC_CHAR nonce[crypto_secretbox_NONCEBYTES]; 17 | } SC_SYM_KEY; 18 | typedef struct { 19 | SC_CHAR mac[crypto_box_MACBYTES]; 20 | SC_CHAR key[crypto_secretbox_KEYBYTES]; 21 | SC_CHAR nonce[crypto_secretbox_NONCEBYTES]; 22 | } SC_ENC_SYM_KEY; 23 | 24 | 25 | const char* shick_crypto_version(); 26 | 27 | /* 28 | * Call this before once, before using any shick_crypto function. 29 | */ 30 | void shick_crypto_init(); 31 | 32 | /* 33 | * Creates a asymmetric secret/public key pair. The size of the keys are 34 | * unsigned char pk[crypto_box_PUBLICKEYBYTES]; 35 | * unsigned char sk[crypto_box_SECRETKEYBYTES]; 36 | */ 37 | int shick_crypto_create_asymmetric_key_pair(SC_CHAR secret_key[crypto_box_SECRETKEYBYTES], SC_CHAR public_key[crypto_box_PUBLICKEYBYTES]); 38 | 39 | void shick_create_nonce(SC_CHAR* nonce, int len); 40 | 41 | int shick_crypto_enc_message(const SC_CHAR sender_secret_key[crypto_box_SECRETKEYBYTES], const SC_CHAR** recipient_public_keys, const int amount_of_recipients, const SC_CHAR* message, const SC_LEN message_len, SC_CHAR nonce[crypto_box_NONCEBYTES], SC_ENC_SYM_KEY* encrypted_symmetric_keys, SC_CHAR* ciphertext); 42 | 43 | int shick_crypto_dec_message(const SC_CHAR recipient_secret_key[crypto_box_SECRETKEYBYTES], const SC_CHAR sender_public_key[crypto_box_PUBLICKEYBYTES], const SC_ENC_SYM_KEY encrypted_symmetric_key, const SC_CHAR* ciphertext, const SC_LEN cipertext_len, const SC_CHAR nonce[crypto_box_NONCEBYTES], SC_CHAR* message); 44 | 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | if COND_GCOV 2 | TESTS = unittests acceptancetests gcov 3 | else 4 | TESTS = unittests acceptancetests 5 | endif 6 | 7 | check_PROGRAMS = unittests acceptancetests 8 | 9 | unittests_SOURCES = unittests.c $(top_builddir)/src/shick_crypto.h 10 | unittests_CFLAGS = @CHECK_CFLAGS@ 11 | unittests_LDADD = $(top_builddir)/src/libshickcrypto.la @CHECK_LIBS@ 12 | 13 | acceptancetests_SOURCES = acceptancetests.c $(top_builddir)/src/shick_crypto.h 14 | acceptancetests_CFLAGS = @CHECK_CFLAGS@ 15 | acceptancetests_LDADD = $(top_builddir)/src/libshickcrypto.la @CHECK_LIBS@ 16 | 17 | -------------------------------------------------------------------------------- /tests/acceptancetests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../src/shick_crypto.h" 6 | 7 | START_TEST (test_shick_crypto_asymmetric_crypto_roundtrip) { 8 | int result = 0; 9 | int amount_of_recipients = 2; 10 | SC_CHAR alice_secret_key[crypto_box_SECRETKEYBYTES]; 11 | SC_CHAR alice_public_key[crypto_box_PUBLICKEYBYTES]; 12 | SC_CHAR bob_secret_key[crypto_box_SECRETKEYBYTES]; 13 | SC_CHAR bob_public_key[crypto_box_PUBLICKEYBYTES]; 14 | SC_CHAR bobby_secret_key[crypto_box_SECRETKEYBYTES]; 15 | SC_CHAR bobby_public_key[crypto_box_PUBLICKEYBYTES]; 16 | const SC_CHAR* recipient_public_keys[amount_of_recipients]; 17 | SC_CHAR nonce[crypto_box_NONCEBYTES]; 18 | SC_CHAR message[] = "Shick Crypto Lib"; 19 | SC_CHAR ciphertext[crypto_box_MACBYTES + sizeof message]; 20 | SC_ENC_SYM_KEY encrypted_symmetric_keys[amount_of_recipients]; 21 | SC_CHAR message_decrypted[sizeof message]; 22 | 23 | shick_crypto_init(); 24 | result = shick_crypto_create_asymmetric_key_pair(alice_secret_key, alice_public_key); 25 | ck_assert_int_eq(result, 0); 26 | result = shick_crypto_create_asymmetric_key_pair(bob_secret_key, bob_public_key); 27 | ck_assert_int_eq(result, 0); 28 | result = shick_crypto_create_asymmetric_key_pair(bobby_secret_key, bobby_public_key); 29 | ck_assert_int_eq(result, 0); 30 | 31 | recipient_public_keys[0] = bob_public_key; 32 | recipient_public_keys[1] = bobby_public_key; 33 | shick_create_nonce(nonce, sizeof nonce); 34 | 35 | // Encrypt 36 | result = shick_crypto_enc_message(alice_secret_key, recipient_public_keys, amount_of_recipients, message, sizeof message, nonce, encrypted_symmetric_keys, ciphertext); 37 | // Now your message is encrypted for Bob and Bobby 38 | // Send (nonce, encrypted_symmetric_keys[i], ciphertext) to Bob and Bobby 39 | ck_assert_int_eq(result, 0); 40 | 41 | /* 42 | printf("Alice' SK:\n"); 43 | for (int c=0; c < crypto_box_SECRETKEYBYTES; c++) { 44 | printf(",0x%02x",(unsigned int) alice_secret_key[c]); 45 | if (c % 8 == 7) printf("\n"); 46 | } 47 | printf("\n"); 48 | printf("Alice' PK:\n"); 49 | for (int c=0; c < crypto_box_PUBLICKEYBYTES; c++) { 50 | printf(",0x%02x",(unsigned int) alice_public_key[c]); 51 | if (c % 8 == 7) printf("\n"); 52 | } 53 | printf("\n"); 54 | printf("Bobs SK:\n"); 55 | for (int c=0; c < crypto_box_SECRETKEYBYTES; c++) { 56 | printf(",0x%02x",(unsigned int) bob_secret_key[c]); 57 | if (c % 8 == 7) printf("\n"); 58 | } 59 | printf("\n"); 60 | printf("Bobs PK:\n"); 61 | for (int c=0; c < crypto_box_PUBLICKEYBYTES; c++) { 62 | printf(",0x%02x",(unsigned int) bob_public_key[c]); 63 | if (c % 8 == 7) printf("\n"); 64 | } 65 | printf("\n"); 66 | printf("Nonce:\n"); 67 | for (int c=0; c < crypto_box_NONCEBYTES; c++) { 68 | printf(",0x%02x",(unsigned int) nonce[c]); 69 | if (c % 8 == 7) printf("\n"); 70 | } 71 | printf("\n"); 72 | printf("Enc Sym Key:\n"); 73 | SC_ENC_SYM_KEY key = encrypted_symmetric_keys[0]; 74 | for (int c=0; c < sizeof(SC_ENC_SYM_KEY); c++) { 75 | printf(",0x%02x",(unsigned int) ((SC_CHAR*) &key)[c]); 76 | if (c % 8 == 7) printf("\n"); 77 | } 78 | printf("\n"); 79 | printf("Cipher Text:\n"); 80 | for (int c=0; c < sizeof ciphertext; c++) { 81 | printf(",0x%02x",(unsigned int) ciphertext[c]); 82 | if (c % 8 == 7) printf("\n"); 83 | } 84 | printf("\n"); 85 | */ 86 | 87 | 88 | // Decrypt for Bob 89 | result = shick_crypto_dec_message(bob_secret_key, alice_public_key, encrypted_symmetric_keys[0], ciphertext, sizeof ciphertext, nonce, message_decrypted); 90 | ck_assert_int_eq(result, 0); 91 | ck_assert_str_eq((const char*) message_decrypted, (const char*) message); 92 | 93 | // Decrypt for Bobby 94 | result = shick_crypto_dec_message(bobby_secret_key, alice_public_key, encrypted_symmetric_keys[1], ciphertext, sizeof ciphertext, nonce, message_decrypted); 95 | ck_assert_int_eq(result, 0); 96 | ck_assert_str_eq((const char*) message_decrypted, (const char*) message); 97 | } 98 | END_TEST 99 | 100 | Suite* shick_crypto_suite(void) { 101 | Suite *s = suite_create ("Shick Crypto Lib - Acceptance Tests"); 102 | 103 | TCase *tc_core = tcase_create ("Core"); 104 | tcase_add_test (tc_core, test_shick_crypto_asymmetric_crypto_roundtrip); 105 | suite_add_tcase (s, tc_core); 106 | 107 | return s; 108 | } 109 | 110 | int main (void) { 111 | int number_failed; 112 | Suite *s = shick_crypto_suite(); 113 | SRunner *sr = srunner_create(s); 114 | srunner_run_all(sr, CK_NORMAL); 115 | number_failed = srunner_ntests_failed(sr); 116 | srunner_free(sr); 117 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 118 | } 119 | 120 | -------------------------------------------------------------------------------- /tests/gcov: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | cd ../src 5 | gcov -o .libs *.c > /dev/null 2> /dev/null 6 | 7 | grep -E -A3 -B3 '(#####)|(SNH)' *.gcov 8 | 9 | if [ $? -eq 0 ]; then 10 | exit 1 11 | else 12 | exit 0 13 | fi 14 | 15 | -------------------------------------------------------------------------------- /tests/unittests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../src/shick_crypto.h" 6 | 7 | const SC_CHAR alicesk[32] = { 8 | 0xdd,0x93,0x5c,0xaf,0xc2,0x71,0x3d,0x07 9 | ,0x61,0x22,0xd3,0x5c,0x7b,0xf9,0x30,0x5f 10 | ,0x68,0x94,0x7f,0xfc,0x43,0xb5,0xb2,0x15 11 | ,0x64,0xc7,0x87,0xaf,0x03,0x7f,0x6b,0xc3 12 | }; 13 | 14 | const SC_CHAR alicepk[32] = { 15 | 0x83,0x0c,0x8e,0xc0,0x8d,0x2d,0x7b,0xb8 16 | ,0x98,0xc5,0x1c,0x59,0x41,0x97,0x32,0x97 17 | ,0x4e,0x58,0x7e,0x0e,0x08,0x5a,0x65,0x16 18 | ,0xd3,0x72,0xcb,0xf4,0xf4,0x18,0x09,0x54 19 | }; 20 | 21 | const SC_CHAR bobsk[32] = { 22 | 0x9c,0xbc,0x27,0x46,0x2c,0x58,0xf9,0x86 23 | ,0x75,0x98,0x2d,0x73,0x51,0xfc,0x6b,0x0f 24 | ,0xf3,0xd0,0x50,0x37,0x4b,0x4e,0x98,0x33 25 | ,0xe6,0xba,0x82,0x5d,0xa1,0x44,0x46,0xc4 26 | }; 27 | 28 | const SC_CHAR bobpk[32] = { 29 | 0x87,0xa1,0x69,0x56,0x60,0xcb,0x1d,0xaa 30 | ,0x4f,0x4a,0xb1,0x48,0x74,0x2c,0x66,0xe1 31 | ,0xee,0xc4,0x8a,0xef,0xe1,0xf2,0x66,0xbc 32 | ,0xdb,0x08,0x7a,0x88,0x36,0x4f,0x3a,0x0c 33 | }; 34 | 35 | const SC_CHAR nonce[24] = { 36 | 0x1f,0x5c,0xe1,0xf5,0x43,0x7d,0xb0,0x57 37 | ,0x53,0x6e,0x13,0x3f,0x55,0xf0,0x80,0x5e 38 | ,0x0e,0x75,0x11,0x5e,0xfe,0xbc,0x9f,0x67 39 | }; 40 | 41 | const SC_CHAR enc_sym_key[72] = { 42 | 0xf2,0x41,0x8d,0x22,0xce,0x24,0x1d,0x2c 43 | ,0x55,0x7a,0xd9,0xce,0xa1,0x8d,0xde,0x52 44 | ,0xf8,0xfb,0x35,0x7b,0x7a,0x07,0x9b,0x9c 45 | ,0xc9,0xc7,0x06,0xe9,0x54,0xaf,0x2f,0x72 46 | ,0x0c,0xd9,0x4e,0x3b,0x9f,0x90,0xe8,0x7d 47 | ,0xec,0x98,0xc2,0x4f,0x7c,0x3d,0x9e,0x37 48 | ,0xc9,0xce,0x54,0x9e,0x7f,0x82,0x96,0xc2 49 | ,0xd8,0xed,0xf5,0xd2,0xd3,0x08,0x30,0xb6 50 | ,0x18,0xdb,0xc3,0xea,0x92,0x8f,0xe8,0x31 51 | }; 52 | 53 | const SC_CHAR message[] = "Shick Crypto Lib"; 54 | 55 | const SC_CHAR ciphertext[33] = { 56 | 0xe5,0xa0,0xcc,0x0b,0xbf,0x84,0x66,0x39 57 | ,0x6e,0x60,0x07,0x25,0x83,0xb8,0x38,0x5f 58 | ,0xd1,0x14,0xe4,0x12,0x19,0xf7,0x84,0x68 59 | ,0x71,0x97,0x48,0x77,0x84,0xdb,0x9a,0x59 60 | ,0x46 61 | }; 62 | 63 | START_TEST (test_shick_crypto_version) { 64 | const char* version = shick_crypto_version(); 65 | ck_assert_str_eq (version, PACKAGE_VERSION); 66 | } 67 | END_TEST 68 | 69 | START_TEST (test_shick_crypto_init) { 70 | shick_crypto_init(); 71 | } 72 | END_TEST 73 | 74 | START_TEST (test_shick_crypto_create_asymmetric_key_pair) { 75 | SC_CHAR secret_key[crypto_box_SECRETKEYBYTES]; 76 | SC_CHAR public_key[crypto_box_PUBLICKEYBYTES]; 77 | shick_crypto_init(); 78 | 79 | int result = shick_crypto_create_asymmetric_key_pair(secret_key, public_key); 80 | 81 | ck_assert_int_eq (result, 0); 82 | } 83 | END_TEST 84 | 85 | START_TEST (test_shick_crypto_create_nonce) { 86 | SC_CHAR zero[crypto_box_NONCEBYTES]; 87 | bzero(zero, sizeof zero); 88 | SC_CHAR nonce[crypto_box_NONCEBYTES]; 89 | bzero(nonce, sizeof zero); 90 | 91 | shick_create_nonce(nonce, sizeof nonce); 92 | 93 | int result = memcmp(nonce, zero, sizeof nonce); 94 | ck_assert_int_ne (result, 0); 95 | } 96 | END_TEST 97 | 98 | START_TEST (test_shick_crypto_enc_messge) { 99 | int result = 0; 100 | SC_CHAR _nonce[crypto_box_NONCEBYTES]; 101 | SC_CHAR encrypted_message[sizeof ciphertext]; 102 | const SC_CHAR* recipient_public_keys[1]; 103 | recipient_public_keys[0] = bobpk; 104 | SC_ENC_SYM_KEY encrypted_symmetric_keys[1]; 105 | 106 | result = shick_crypto_enc_message(alicesk, recipient_public_keys, 1, message, sizeof message, _nonce, encrypted_symmetric_keys, encrypted_message); 107 | ck_assert_int_eq (result, 0); 108 | } 109 | END_TEST 110 | 111 | START_TEST (test_shick_crypto_dec_messge) { 112 | int result = 0; 113 | SC_CHAR message_decrypted[sizeof message]; 114 | 115 | result = shick_crypto_dec_message(bobsk, alicepk, *(SC_ENC_SYM_KEY*) &enc_sym_key, ciphertext, sizeof ciphertext, nonce, message_decrypted); 116 | ck_assert_int_eq (result, 0); 117 | ck_assert_str_eq((const char*) message_decrypted, (const char*) message); 118 | } 119 | END_TEST 120 | 121 | Suite* shick_crypto_suite(void) { 122 | Suite *s = suite_create ("Shick Crypto Lib - Unit Tests"); 123 | 124 | TCase *tc_core = tcase_create ("Core"); 125 | tcase_add_test (tc_core, test_shick_crypto_version); 126 | tcase_add_test (tc_core, test_shick_crypto_init); 127 | tcase_add_test (tc_core, test_shick_crypto_create_asymmetric_key_pair); 128 | tcase_add_test (tc_core, test_shick_crypto_create_nonce); 129 | tcase_add_test (tc_core, test_shick_crypto_enc_messge); 130 | tcase_add_test (tc_core, test_shick_crypto_dec_messge); 131 | suite_add_tcase (s, tc_core); 132 | 133 | return s; 134 | } 135 | 136 | int main (void) { 137 | int number_failed; 138 | Suite *s = shick_crypto_suite(); 139 | SRunner *sr = srunner_create(s); 140 | srunner_run_all(sr, CK_NORMAL); 141 | number_failed = srunner_ntests_failed(sr); 142 | srunner_free(sr); 143 | return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 144 | } 145 | 146 | --------------------------------------------------------------------------------