Created
July 29, 2017 22:16
-
-
Save berenoguz/278a0f52d1b5757fdd603602cdedcc15 to your computer and use it in GitHub Desktop.
A minimal, but functional implementation of ChaCha20 stream cipher (RFC 7539)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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