Giter VIP home page Giter VIP logo

abderraouf-adjal / arduinospritzcipher Goto Github PK

View Code? Open in Web Editor NEW
75.0 7.0 14.0 658 KB

Spritz encryption system portable C library, CSPRNG, cryptographic hash and MAC functions, symmetric-key data encryption, and general-purpose functions. It's also an Arduino library.

License: ISC License

C 100.00%
arduino arduino-library spritz crypto cryptography crypto-library embedded spritz-library hash random-bytes

arduinospritzcipher's Introduction

Spritz Library For Arduino

Spritz - a spongy RC4-like stream cipher and hash function.

This library contains a cryptographic pseudo-random number generator, cryptographic hash and message authentication code (MAC) functions, can perform symmetric-key authenticated data encryption, and general-purpose functions for timing-safe comparison and wiping data from memory.

This C Spritz library can be used to:

  • Hash and authenticate data.
  • Perform symmetric-key authenticated data encryption.
  • Generate random numbers and strings from entropy/seed.

This library's GitHub repository.

This library's Bitbucket repository (Backup).

Spritz paper: https://people.csail.mit.edu/rivest/pubs/RS14.pdf


Library Content

Read the source code for details.

Types

spritz_ctx - The context/ctx (contains the state). The state consists of byte registers {i, j, k, z, w, a}, And an array {s} containing a permutation of {0, 1, ... , SPRITZ_N-1}.

uint8_t - unsigned integer type with width of 8-bit, MIN=0;MAX=255.

uint16_t - unsigned integer type with width of 16-bit, MIN=0;MAX=65,535.

uint32_t - unsigned integer type with width of 32-bit, MIN=0;MAX=4,294,967,295.

Functions

uint8_t spritz_compare(const uint8_t *data_a, const uint8_t *data_b,
                       uint16_t len)

Timing-safe comparison for data_a and data_b equality. This function can be used to compare the password's hash safely.

Return equality result. Zero (0x00) if data_a equals data_b OR if len is zero, Non-zero value if they are NOT equal.

void spritz_memzero(uint8_t *buf, uint16_t len)

Wipe buf data by replacing it with len zeros (0x00).

void spritz_state_memzero(spritz_ctx *ctx)

Wipe spritz_ctx's data by replacing its data with zeros (0x00).

If SPRITZ_WIPE_TRACES_PARANOID is defined, This function will wipe the sensitive temporary variables in spritz_ctx.

void spritz_setup(spritz_ctx *ctx,
                  const uint8_t *key, uint8_t keyLen)

Setup the spritz state spritz_ctx with a key of length keyLen.

void spritz_setup_withIV(spritz_ctx *ctx,
                         const uint8_t *key, uint8_t keyLen,
                         const uint8_t *nonce, uint8_t nonceLen)

Setup the spritz state spritz_ctx with a key and nonce/Salt/IV.

uint8_t spritz_random8(spritz_ctx *ctx)

Generates a random byte (8-bit) from the spritz state spritz_ctx.

uint32_t spritz_random32(spritz_ctx *ctx)

Generates a random 32-bit (4 bytes) from the spritz state spritz_ctx.

uint32_t spritz_random32_uniform(spritz_ctx *ctx, uint32_t upper_bound)

Calculate an uniformly distributed random number less than upper_bound avoiding modulo bias. Uniformity is achieved by generating new random numbers until the one returned is outside the range [0, 2**32 % upper_bound). This guarantees the selected random number will be inside [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) after reduction modulo upper_bound.

void spritz_add_entropy(spritz_ctx *ctx,
                        const uint8_t *entropy, uint16_t len)

Add entropy to the spritz state spritz_ctx using the internal function absorb().

void spritz_crypt(spritz_ctx *ctx,
                  const uint8_t *data, uint16_t dataLen,
                  uint8_t *dataOut)

Encrypt or decrypt data chunk by XOR-ing it with the spritz keystream.

void spritz_crypt_inplace(spritz_ctx *ctx,
                          uint8_t *data, uint16_t dataLen)

Encrypt or decrypt data chunk by XOR-ing it with the spritz keystream and put the output in the same buffer data.

void spritz_hash(uint8_t *digest, uint8_t digestLen,
                 const uint8_t *data, uint16_t dataLen)

Spritz cryptographic hash function.

void spritz_mac(uint8_t *digest, uint8_t digestLen,
                const uint8_t *msg, uint16_t msgLen,
                const uint8_t *key, uint16_t keyLen)

Spritz Message Authentication Code (MAC) function.

void spritz_hash_setup(spritz_ctx *hash_ctx)

Setup the spritz hash state.

void spritz_hash_update(spritz_ctx *hash_ctx,
                        const uint8_t *data, uint16_t dataLen)

Add a message/data chunk data to hash.

void spritz_hash_final(spritz_ctx *hash_ctx,
                       uint8_t *digest, uint8_t digestLen)

Output the hash digest.

void spritz_mac_setup(spritz_ctx *mac_ctx,
                      const uint8_t *key, uint16_t keyLen)

Setup the spritz Message Authentication Code (MAC) state.

void spritz_mac_update(spritz_ctx *mac_ctx,
                       const uint8_t *msg, uint16_t msgLen)

Add a message/data chunk to Message Authentication Code (MAC).

void spritz_mac_final(spritz_ctx *mac_ctx,
                      uint8_t *digest, uint8_t digestLen)

Output the Message Authentication Code (MAC) digest.

Notes

spritz_random8(), spritz_random32(), spritz_random32_uniform(), spritz_add_entropy(), spritz_crypt(). Are usable only after calling spritz_setup() or spritz_setup_withIV().

Functions spritz_random*() requires spritz_setup() or spritz_setup_withIV() initialized with an entropy (random data), 128-bit of entropy at least. Arduino Uno's ATmega328P and many microcontrollers and microprocessors does NOT have a real/official way to get entropy,

you will/may need getting entropy by using hardware (recommended), or at least a pre-stored random data updated with spritz_random*() output (NOT recommended).

To generate a random number in a range [k, m) use k + spritz_random32_uniform(ctx, m), Not k + (spritz_random8(ctx) % m) or k + (spritz_random32(ctx) % m).

Use spritz_state_memzero() after spritz_hash_final() or spritz_mac_final() if you need to wipe the used spritz_ctx's data.

Constants

Configure library settings in the file SpritzCipher.h.

  • SPRITZ_USE_LIBC

Use C standard library functions such as memset() to zero buffers. It can be useful for performnce if the lib-C functions are optimized in low-level. If the compiler is not GCC or Clang, you will see a security warning about code optimization is not off in some sensitive functions.

SPRITZ_USE_LIBC is NOT defined by default.

  • SPRITZ_TIMING_SAFE_CRUSH

If defined, The equal time crush() will be used.

SPRITZ_TIMING_SAFE_CRUSH is defined by default.

  • SPRITZ_WIPE_TRACES

If defined, Sensitive data like spritz_ctx will be wiped, when they are no longer needed, in the functions: spritz_hash(), spritz_mac().

SPRITZ_WIPE_TRACES is NOT defined by default.

  • SPRITZ_WIPE_TRACES_PARANOID

If defined, The library functions internal variables will be wiped if they contain a bit or more of spritz state, such as temporary variables in a swap function or user data. Variables that contain data length will not be wiped.

If SPRITZ_WIPE_TRACES_PARANOID defined, Then SPRITZ_WIPE_TRACES and SPRITZ_TIMING_SAFE_CRUSH, will be defined automatically.

SPRITZ_WIPE_TRACES_PARANOID is NOT defined by default.

  • SPRITZ_N = 256 - Present the value of N in this spritz implementation, Do NOT change SPRITZ_N value.

  • SPRITZ_LIBRARY_VERSION_STRING = "x.y.z" - Present the version of this spritz library (MAJOR . MINOR . PATCH) using Semantic Versioning.

  • SPRITZ_LIBRARY_VERSION_MAJOR = x - The MAJOR version of the library.

  • SPRITZ_LIBRARY_VERSION_MINOR = y - The MINOR version of the library.

  • SPRITZ_LIBRARY_VERSION_PATCH = z - The PATCH version of the library.


Examples

  • SpritzBestPractice: Hash 32 KB of a Spritz stream (pseudo-random number generator output) then print the result. An embedded entropy/seed for the pseudo-random number generator is used.

  • SpritzBestPracticePassword: Generate a strong Alphanumeric passwords, and then print it. An embedded entropy/seed for the pseudo-random number generator is used.

  • SpritzBestPracticePasswordESP8266: Generate a strong Alphanumeric passwords, and then print it. This example is for ESP8266 SoC, it uses a hardware RNG in ESP8266 as an initialization entropy.

  • SpritzCryptTest: Test the library encryption/decryption function.

  • SpritzCryptInplaceTest: Test the library encryption/decryption function doing encrypt and decrypt in same buffer for less RAM usage.

  • SpritzStreamTest: Generate random bytes (Spritz stream) test.

  • SpritzHashTest: Hash function test.

  • SpritzMACTest: Message authentication code (MAC) function test.


Installation Guide

Arduino IDE - Additional libraries installation guide.

Compiling this library using GCC or Clang will give more security for functions that should be compiled with zero optimization (-O0) like spritz_compare().


Reporting bugs

Create an issue on GitHub.


Copyright and License

Copyright (c) 2015-2020 Abderraouf Adjal

  • The source-code: ISC License.

  • Documentation (e.g. this file content): Public domain.

  • Examples: Public domain.

arduinospritzcipher's People

Contributors

abderraouf-adjal avatar per1234 avatar shlomif avatar sidwarkd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

arduinospritzcipher's Issues

spritz_random32(spritz_ctx *ctx) - faster?

expect some performance gain from this implementation as it does 50% less shifts and no casting
however it might be that the bytes are ordered differently (for randomness that should not matter...?)

uint32_t spritz_random32(spritz_ctx *ctx)
{
  uint32_t rv = drip(ctx);
  for (uint8_t i = 0; i < 3; i++)
 {
    rv <<= 8;
   rv |= drip(ctx);
 }
 return rv;
}

probably even faster when using an union of an uint32_t and an array of 4 bytes.
https://en.cppreference.com/w/cpp/language/union

uint32_t spritz_random32(spritz_ctx *ctx)
{
  union
  {
    uint32_t rv;
    uint8_t ar[4];
  } u;
  for (uint8_t i = 0; i < 4; i++)
 {
    u.ar[i] = drip(ctx);
 }
 return u.rv;
}

How to make this compatible with ARC4 / RC4?

Hi I have an Arduino application that requires compatibility with ARC4.

I have the SpritzCipher library already installed and I like it a lot so is there a way that I can initialise the cipher so that it remove all additional features of the Spritz algorithm and becomes compatible with ARC4/RC4?

I realise this reduces security but it would be good to have this flexibility when required.

Please let me know thanks!

#ifdef SPRITZ_WIPE_TRACES_PARANOID

Think this paranoid code can be much simpler, smaller and probably faster

  d |= d >> 1; /* |_|_|_|_|_|_|S|D| `D |= S` */
  d |= d >> 2; /* |_|_|_|_|_|S|_|D| */
  d |= d >> 3; /* |_|_|_|_|S|_|_|D| */
  d |= d >> 4; /* |_|_|_|S|_|_|_|D| */
  d |= d >> 5; /* |_|_|S|_|_|_|_|D| */
  d |= d >> 6; /* |_|S|_|_|_|_|_|D| */
  d |= d >> 7; /* |S|_|_|_|_|_|_|D| */
  d &= 1;      /* |0|0|0|0|0|0|0|D| Zero all bits except LSB */
 d = (d !=  0) : 1 : 0;

Is this library usable to cypher data on one device and decypher on another one ?

Hi
I struggle using this library to transmit cyphered data between two devices.
Lets say I have one device creating, cyphering and transmitting data ; and another one receiving, decyphering and using data.

I setup the lib with key and nonce the same way on both devices.

const byte key[8] = {0x13, 0xAB, 0xA2, 0x5C, 0xA3, 0x45, 0x98, 0x78};
const byte nonce[4] = {0xCA, 0x12, 0x45, 0x65};

spritz_ctx s_ctx;

spritz_setup_withIV(&s_ctx, key, sizeof(key), nonce, sizeof(nonce) );

I can decypher properly data on the RX side ONLY when both devices have booted roughly at the same time. If I restart only one of them, then the decyphered data is garbage.

Is there another initialization needed to set context ? Does the clock time is used to generate an internal seed ?

I did not see any "limitation" of this kind in documentation.

PS : I am aware that having this pre-shared key in both device and no actual random seed is not the way to really protect data, but my goal here is to obfuscate the data being transmitted over the air.

Improve Entropy Pool

Hello!
So, a fixed entropy pool in a PRNG is a bad idea, as the PRNG will give precisely the same output every time it is reset (which can happen quite a bit with embedded systems, let's be honest). In short, it gives a random number set that can be rainbow tabled with high precision, which would potentially compromise the encryption relying on this random number generation.
To fix this, I've done some testing on Arduinos that might help? Here is a link: https://medium.com/@LargeCardinal/random-numbers-on-the-arduino-97f325820284
I would recommend using the WDT Jitter and some other source such as the thermal noise on A8. If you use this as the initial entropy pool, it would improve the situation considerably. :D
I'd write a patch, but I'm currently up to my eyeballs in work, so it would take some time for me to do, but getting fair bits that are perperly random for your entropy pool shouldn't be too hard.
NB - this might add a startup lag to the device, so you may with to have this off by default, turned on if it's important? We have to be realistic about device startup times, of course. :)
Happy to answer any questions!
Cheers, M.

spritz_random32_uniform

this random function will work in practice, however depending on the UPPER bound (esp large values) it is not uniform

imagine your random generator generates 0 .. 9
and you set the upper bound to 7
then the numbers 0,1,2 have twice as many chance of being chosen than numbers 3,4,5,6,7,8 and 9.
this is because UPPER and MAX random are same order of magnitude.

When UPPER bound is small it is still not uniform but the bias will be substantial smaller (less problematic)

new function - spritz_crypt_inplace

spritz_crypt_inplace(spritz_ctx *ctx, uint8_t *data, uint16_t dataLen)
{
  uint16_t i = dataLen;
  while( i > 0)    // cmp with zero is fast
  {
    data[--i] ^= drip(ctx);
  }
}

Encrypt/decrypt success rate a function of key size

When performing encrypt followed by decrypt, the success rate (defined as the frequency at which the plaintext is regenerated) appears to be dependent on the key length. I ran repetitive encrypt/decrypt cycles with different key lengths and found that:
A key length of 128 bytes results in about a 2% success rate
64 byte key results in about 75%
48 byte key results in about 80%
32 byte key results in about 90%
16 byte key results in about 98%

Each of these tests ran for over 2000 cycles.

Here's the code:
`#include <SpritzCipher.h>

long total = 0;
long success = 0;

const PROGMEM byte key[16] = {0xF4, 0x88, 0xE6, 0x3B, 0xA3, 0x1A, 0x79, 0x7F, 0x8D, 0x4C, 0x10, 0xEC, 0xB2, 0x1F, 0x84, 0x91};

void spritzEnc(byte msg[], byte msgLen, const byte *key, byte keyLen){
spritz_ctx s_ctx;

spritz_setup(&s_ctx, key, keyLen);
spritz_crypt(&s_ctx, msg, msgLen, msg);
}

void spritzDec(byte msg[], byte msgLen, const byte *key, byte keyLen){
spritz_ctx s_ctx;

spritz_setup(&s_ctx, key, keyLen);
spritz_crypt(&s_ctx, msg, msgLen, msg);
}

void setup() {
/* Initialize serial and wait for port to open /
Serial.begin(9600);
while (!Serial) {
; /
Wait for serial port to connect. Needed for Leonardo only */
}

/* initialize digital pin LED_BUILTIN (Most boards have this LED connected to digital pin 13) as an output */
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
byte testMsg[4] = { 'A', 'B', 'C', 'S'};

spritzEnc(testMsg, sizeof(testMsg), key, sizeof(key)); // Encrypt

spritzDec(testMsg, sizeof(testMsg), key, sizeof(key)); // Decrypt

if (testMsg[0] == 'A' && testMsg[1] == 'B' && testMsg[2] == 'C' && testMsg[3] == 'S'){
success = success + 1;
}
total = total + 1;
float sp = (float(success) / float(total))*100.0;

Serial.print("Cycles = ");
Serial.print(total);
Serial.print(" success = ");
Serial.print(success);
Serial.print(" or ");
Serial.print(sp, 2);
Serial.println(" %");

}
`

non standard implementation?

Perhaps more of a note than a bug. This library does not produce outputs that agree with common libs such as https://github.com/therealjampers/spritzjs/ .
While both produce the same results as the test vectors in the paper here: https://people.csail.mit.edu/rivest/pubs/RS14.pdf , This lib uses XOR for encrypt as opposed to what is used in the paper/ other libs which is modular addition / modular subtraction.
example solution:

void spritz_crypt(spritz_ctx *ctx, const uint8_t *data, uint16_t dataLen, uint8_t *dataOut) { uint16_t i; uint16_t temp = 0; for (i = 0; i < dataLen; i++) { temp = data[i] + drip(ctx); temp %=256; //dataOut[i] = data[i] ^ drip(ctx); dataOut[i] = temp; } }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.