chacha.c revision 261287
146432Sphk/* 246432Sphkchacha-merged.c version 20080118 346432SphkD. J. Bernstein 446432SphkPublic domain. 546432Sphk*/ 646432Sphk 746432Sphk#include "includes.h" 846432Sphk 946432Sphk#include "chacha.h" 10117280Scharnier 11117280Scharnier/* $OpenBSD: chacha.c,v 1.1 2013/11/21 00:45:44 djm Exp $ */ 12117280Scharnier 13112705Smaximtypedef unsigned char u8; 1446155Sphktypedef unsigned int u32; 15158428Smatteo 1678723Sddtypedef struct chacha_ctx chacha_ctx; 1746155Sphk 1878723Sdd#define U8C(v) (v##U) 1946155Sphk#define U32C(v) (v##U) 2078723Sdd 21129848Smaxim#define U8V(v) ((u8)(v) & U8C(0xFF)) 22112705Smaxim#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) 23112705Smaxim 24133743Smaxim#define ROTL32(v, n) \ 25112705Smaxim (U32V((v) << (n)) | ((v) >> (32 - (n)))) 2678723Sdd 2778723Sdd#define U8TO32_LITTLE(p) \ 2878723Sdd (((u32)((p)[0]) ) | \ 2978723Sdd ((u32)((p)[1]) << 8) | \ 3078723Sdd ((u32)((p)[2]) << 16) | \ 31112705Smaxim ((u32)((p)[3]) << 24)) 32158428Smatteo 33133743Smaxim#define U32TO8_LITTLE(p, v) \ 34112705Smaxim do { \ 35129848Smaxim (p)[0] = U8V((v) ); \ 36129848Smaxim (p)[1] = U8V((v) >> 8); \ 37129848Smaxim (p)[2] = U8V((v) >> 16); \ 38129848Smaxim (p)[3] = U8V((v) >> 24); \ 39129848Smaxim } while (0) 40129848Smaxim 41129848Smaxim#define ROTATE(v,c) (ROTL32(v,c)) 42129848Smaxim#define XOR(v,w) ((v) ^ (w)) 43129848Smaxim#define PLUS(v,w) (U32V((v) + (w))) 44129848Smaxim#define PLUSONE(v) (PLUS((v),1)) 45129848Smaxim 46129848Smaxim#define QUARTERROUND(a,b,c,d) \ 47129848Smaxim a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ 48129848Smaxim c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ 49129848Smaxim a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ 50129848Smaxim c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); 5146155Sphk 5246155Sphkstatic const char sigma[16] = "expand 32-byte k"; 5346155Sphkstatic const char tau[16] = "expand 16-byte k"; 54137808Sdelphij 5546155Sphkvoid 56137808Sdelphijchacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits) 5746155Sphk{ 58136051Sstefanf const char *constants; 59153056Sphilip 60153056Sphilip x->input[4] = U8TO32_LITTLE(k + 0); 61133743Smaxim x->input[5] = U8TO32_LITTLE(k + 4); 62137807Sdelphij x->input[6] = U8TO32_LITTLE(k + 8); 63158428Smatteo x->input[7] = U8TO32_LITTLE(k + 12); 64153056Sphilip if (kbits == 256) { /* recommended */ 6546155Sphk k += 16; 66153056Sphilip constants = sigma; 67153056Sphilip } else { /* kbits == 128 */ 68153056Sphilip constants = tau; 69112705Smaxim } 70158428Smatteo x->input[8] = U8TO32_LITTLE(k + 0); 71112705Smaxim x->input[9] = U8TO32_LITTLE(k + 4); 72113277Smike x->input[10] = U8TO32_LITTLE(k + 8); 73113277Smike x->input[11] = U8TO32_LITTLE(k + 12); 74113277Smike x->input[0] = U8TO32_LITTLE(constants + 0); 75153056Sphilip x->input[1] = U8TO32_LITTLE(constants + 4); 76153056Sphilip x->input[2] = U8TO32_LITTLE(constants + 8); 77153056Sphilip x->input[3] = U8TO32_LITTLE(constants + 12); 78153056Sphilip} 79158428Smatteo 80158428Smatteovoid 81158428Smatteochacha_ivsetup(chacha_ctx *x, const u8 *iv, const u8 *counter) 82112705Smaxim{ 83112705Smaxim x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0); 84129848Smaxim x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4); 85112705Smaxim x->input[14] = U8TO32_LITTLE(iv + 0); 86129848Smaxim x->input[15] = U8TO32_LITTLE(iv + 4); 87129848Smaxim} 88129848Smaxim 89129848Smaximvoid 90133743Smaximchacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) 91133743Smaxim{ 92133743Smaxim u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; 93112705Smaxim u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; 94112705Smaxim u8 *ctarget = NULL; 95112705Smaxim u8 tmp[64]; 96113277Smike u_int i; 97112705Smaxim 98112705Smaxim if (!bytes) return; 99112705Smaxim 100112705Smaxim j0 = x->input[0]; 101129848Smaxim j1 = x->input[1]; 102129848Smaxim j2 = x->input[2]; 103133743Smaxim j3 = x->input[3]; 104133743Smaxim j4 = x->input[4]; 105129848Smaxim j5 = x->input[5]; 106129848Smaxim j6 = x->input[6]; 107131182Spjd j7 = x->input[7]; 108131182Spjd j8 = x->input[8]; 109131182Spjd j9 = x->input[9]; 110131182Spjd j10 = x->input[10]; 11151399Sphk j11 = x->input[11]; 11251399Sphk j12 = x->input[12]; 113131182Spjd j13 = x->input[13]; 114112705Smaxim j14 = x->input[14]; 115112972Smaxim j15 = x->input[15]; 116112972Smaxim 11746432Sphk for (;;) { 118153056Sphilip if (bytes < 64) { 119153056Sphilip for (i = 0;i < bytes;++i) tmp[i] = m[i]; 120153056Sphilip m = tmp; 121153056Sphilip ctarget = c; 122153056Sphilip c = tmp; 123113277Smike } 124113277Smike x0 = j0; 125112972Smaxim x1 = j1; 126113804Smike x2 = j2; 127113277Smike x3 = j3; 128113804Smike x4 = j4; 129113804Smike x5 = j5; 130153056Sphilip x6 = j6; 131153056Sphilip x7 = j7; 132153056Sphilip x8 = j8; 133153056Sphilip x9 = j9; 134153056Sphilip x10 = j10; 135153056Sphilip x11 = j11; 136153056Sphilip x12 = j12; 137153056Sphilip x13 = j13; 138153056Sphilip x14 = j14; 139158428Smatteo x15 = j15; 140158428Smatteo for (i = 20;i > 0;i -= 2) { 141112705Smaxim QUARTERROUND( x0, x4, x8,x12) 142129848Smaxim QUARTERROUND( x1, x5, x9,x13) 143129848Smaxim QUARTERROUND( x2, x6,x10,x14) 144133743Smaxim QUARTERROUND( x3, x7,x11,x15) 145133743Smaxim QUARTERROUND( x0, x5,x10,x15) 146133743Smaxim QUARTERROUND( x1, x6,x11,x12) 147133743Smaxim QUARTERROUND( x2, x7, x8,x13) 148112972Smaxim QUARTERROUND( x3, x4, x9,x14) 149112972Smaxim } 150112972Smaxim x0 = PLUS(x0,j0); 151112972Smaxim x1 = PLUS(x1,j1); 152112972Smaxim x2 = PLUS(x2,j2); 153157790Smaxim x3 = PLUS(x3,j3); 154112972Smaxim x4 = PLUS(x4,j4); 155113206Smaxim x5 = PLUS(x5,j5); 156112705Smaxim x6 = PLUS(x6,j6); 157133743Smaxim x7 = PLUS(x7,j7); 158133743Smaxim x8 = PLUS(x8,j8); 159133743Smaxim x9 = PLUS(x9,j9); 160133743Smaxim x10 = PLUS(x10,j10); 161133743Smaxim x11 = PLUS(x11,j11); 162133743Smaxim x12 = PLUS(x12,j12); 163133743Smaxim x13 = PLUS(x13,j13); 164133743Smaxim x14 = PLUS(x14,j14); 165133743Smaxim x15 = PLUS(x15,j15); 166133743Smaxim 167133743Smaxim x0 = XOR(x0,U8TO32_LITTLE(m + 0)); 168133743Smaxim x1 = XOR(x1,U8TO32_LITTLE(m + 4)); 169133743Smaxim x2 = XOR(x2,U8TO32_LITTLE(m + 8)); 170112972Smaxim x3 = XOR(x3,U8TO32_LITTLE(m + 12)); 171112972Smaxim x4 = XOR(x4,U8TO32_LITTLE(m + 16)); 172113277Smike x5 = XOR(x5,U8TO32_LITTLE(m + 20)); 17346155Sphk x6 = XOR(x6,U8TO32_LITTLE(m + 24)); 174112705Smaxim x7 = XOR(x7,U8TO32_LITTLE(m + 28)); 175112705Smaxim x8 = XOR(x8,U8TO32_LITTLE(m + 32)); 176112705Smaxim x9 = XOR(x9,U8TO32_LITTLE(m + 36)); 177112705Smaxim x10 = XOR(x10,U8TO32_LITTLE(m + 40)); 178112705Smaxim x11 = XOR(x11,U8TO32_LITTLE(m + 44)); 179158428Smatteo x12 = XOR(x12,U8TO32_LITTLE(m + 48)); 180158428Smatteo x13 = XOR(x13,U8TO32_LITTLE(m + 52)); 181158428Smatteo x14 = XOR(x14,U8TO32_LITTLE(m + 56)); 182129848Smaxim x15 = XOR(x15,U8TO32_LITTLE(m + 60)); 183112972Smaxim 184112705Smaxim j12 = PLUSONE(j12); 185158428Smatteo if (!j12) { 186158428Smatteo j13 = PLUSONE(j13); 187158428Smatteo /* stopping at 2^70 bytes per nonce is user's responsibility */ 188158428Smatteo } 189158428Smatteo 190158428Smatteo U32TO8_LITTLE(c + 0,x0); 191158428Smatteo U32TO8_LITTLE(c + 4,x1); 192158428Smatteo U32TO8_LITTLE(c + 8,x2); 193 U32TO8_LITTLE(c + 12,x3); 194 U32TO8_LITTLE(c + 16,x4); 195 U32TO8_LITTLE(c + 20,x5); 196 U32TO8_LITTLE(c + 24,x6); 197 U32TO8_LITTLE(c + 28,x7); 198 U32TO8_LITTLE(c + 32,x8); 199 U32TO8_LITTLE(c + 36,x9); 200 U32TO8_LITTLE(c + 40,x10); 201 U32TO8_LITTLE(c + 44,x11); 202 U32TO8_LITTLE(c + 48,x12); 203 U32TO8_LITTLE(c + 52,x13); 204 U32TO8_LITTLE(c + 56,x14); 205 U32TO8_LITTLE(c + 60,x15); 206 207 if (bytes <= 64) { 208 if (bytes < 64) { 209 for (i = 0;i < bytes;++i) ctarget[i] = c[i]; 210 } 211 x->input[12] = j12; 212 x->input[13] = j13; 213 return; 214 } 215 bytes -= 64; 216 c += 64; 217 m += 64; 218 } 219} 220