Skip to content

Instantly share code, notes, and snippets.

@berenoguz
Created July 29, 2017 22:16
Show Gist options
  • Save berenoguz/278a0f52d1b5757fdd603602cdedcc15 to your computer and use it in GitHub Desktop.
Save berenoguz/278a0f52d1b5757fdd603602cdedcc15 to your computer and use it in GitHub Desktop.
A minimal, but functional implementation of ChaCha20 stream cipher (RFC 7539)
/**
* @author Beren Oguz <beren@berkeley.edu>
*
* @date 29 July 2017
*
* This is a minimal, but functional, implementation of ChaCha20 ciphering
* algorithm. Please read and understand RFC 7539 standard here:
* https://tools.ietf.org/html/rfc7539
* Please make sure you understand how the memory layout of input to ChaCha20
* works before using this function.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
/**
* Integer rotate leftward
*/
void _chacha20_rotl(uint32_t *value, int shift);
/**
* ChaCha20 Quarter Round
*/
void _chacha20_quarter_round(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d);
/*
* @input
* data: 16 unsigned integers, disregard first 4
* of them since they will be overriden. In
* other words, data[0], data[1], data[2] and
* data[3] is not part of the input.
*
* @output
* data: 16 random unsigned integers.
*
* @warning due to an implementation detail in my own
* code, I implemented this function destructively
* editing the whole array `data`, and, therefore,
* I had to make the awkward choice of disregarding
* first 4 integers of `data`. You should read
* https://tools.ietf.org/html/rfc7539 and understand
* how ChaCha20 algorithm works before using it.
*/
#define QROUND(x,y,z,t) _chacha20_quarter_round(&data[x], &data[y], &data[z], &data[t])
void chacha20(uint32_t data[32])
{
data[0] = 0x61707865;
data[1] = 0x3320646e;
data[2] = 0x79622d32;
data[3] = 0x6b206574;
uint32_t working_state[16];
memcpy(working_state, data, 16 * sizeof(uint32_t));
for (int i = 0; i < 10; ++i) {
QROUND(0, 4, 8,12);
QROUND(1, 5, 9,13);
QROUND(2, 6,10,14);
QROUND(3, 7,11,15);
QROUND(0, 5,10,15);
QROUND(1, 6,11,12);
QROUND(2, 7, 8,13);
QROUND(3, 4, 9,14);
}
for (int i = 0; i < 16; ++i) {
data[i] += working_state[i];
}
}
#undef QROUND
/**
* Sample chacha20 ciphering in https://tools.ietf.org/html/rfc7539
*/
int main()
{
char data[64] = {
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
1,0,0,0,
0, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00
};
uint32_t d[16];
memcpy(d, data, 64);
chacha20(d);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
printf("%.8x ", d[i*4+j]);
}
printf("\n");
}
memcpy(data, d, 64);
for (int i = 0; i < 64; ++i) {
printf("%x ", (unsigned char) data[i]);
}
}
void _chacha20_rotl(uint32_t *value, int shift) {
*value = (*value << shift) | (*value >> (sizeof(*value)*8 - shift));
}
void _chacha20_quarter_round(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
{
*a += *b;
*d ^= *a;
_chacha20_rotl(d, 16);
*c += *d;
*b ^= *c;
_chacha20_rotl(b, 12);
*a += *b;
*d ^= *a;
_chacha20_rotl(d, 8);
*c += *d;
*b ^= *c;
_chacha20_rotl(b, 7);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment