]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - lib/chacha20.c
random: replace non-blocking pool with a Chacha20-based CRNG
[mirror_ubuntu-artful-kernel.git] / lib / chacha20.c
diff --git a/lib/chacha20.c b/lib/chacha20.c
new file mode 100644 (file)
index 0000000..250ceed
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * ChaCha20 256-bit cipher algorithm, RFC7539
+ *
+ * Copyright (C) 2015 Martin Willi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/bitops.h>
+#include <linux/cryptohash.h>
+#include <asm/unaligned.h>
+#include <crypto/chacha20.h>
+
+static inline u32 rotl32(u32 v, u8 n)
+{
+       return (v << n) | (v >> (sizeof(v) * 8 - n));
+}
+
+extern void chacha20_block(u32 *state, void *stream)
+{
+       u32 x[16], *out = stream;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(x); i++)
+               x[i] = state[i];
+
+       for (i = 0; i < 20; i += 2) {
+               x[0]  += x[4];    x[12] = rotl32(x[12] ^ x[0],  16);
+               x[1]  += x[5];    x[13] = rotl32(x[13] ^ x[1],  16);
+               x[2]  += x[6];    x[14] = rotl32(x[14] ^ x[2],  16);
+               x[3]  += x[7];    x[15] = rotl32(x[15] ^ x[3],  16);
+
+               x[8]  += x[12];   x[4]  = rotl32(x[4]  ^ x[8],  12);
+               x[9]  += x[13];   x[5]  = rotl32(x[5]  ^ x[9],  12);
+               x[10] += x[14];   x[6]  = rotl32(x[6]  ^ x[10], 12);
+               x[11] += x[15];   x[7]  = rotl32(x[7]  ^ x[11], 12);
+
+               x[0]  += x[4];    x[12] = rotl32(x[12] ^ x[0],   8);
+               x[1]  += x[5];    x[13] = rotl32(x[13] ^ x[1],   8);
+               x[2]  += x[6];    x[14] = rotl32(x[14] ^ x[2],   8);
+               x[3]  += x[7];    x[15] = rotl32(x[15] ^ x[3],   8);
+
+               x[8]  += x[12];   x[4]  = rotl32(x[4]  ^ x[8],   7);
+               x[9]  += x[13];   x[5]  = rotl32(x[5]  ^ x[9],   7);
+               x[10] += x[14];   x[6]  = rotl32(x[6]  ^ x[10],  7);
+               x[11] += x[15];   x[7]  = rotl32(x[7]  ^ x[11],  7);
+
+               x[0]  += x[5];    x[15] = rotl32(x[15] ^ x[0],  16);
+               x[1]  += x[6];    x[12] = rotl32(x[12] ^ x[1],  16);
+               x[2]  += x[7];    x[13] = rotl32(x[13] ^ x[2],  16);
+               x[3]  += x[4];    x[14] = rotl32(x[14] ^ x[3],  16);
+
+               x[10] += x[15];   x[5]  = rotl32(x[5]  ^ x[10], 12);
+               x[11] += x[12];   x[6]  = rotl32(x[6]  ^ x[11], 12);
+               x[8]  += x[13];   x[7]  = rotl32(x[7]  ^ x[8],  12);
+               x[9]  += x[14];   x[4]  = rotl32(x[4]  ^ x[9],  12);
+
+               x[0]  += x[5];    x[15] = rotl32(x[15] ^ x[0],   8);
+               x[1]  += x[6];    x[12] = rotl32(x[12] ^ x[1],   8);
+               x[2]  += x[7];    x[13] = rotl32(x[13] ^ x[2],   8);
+               x[3]  += x[4];    x[14] = rotl32(x[14] ^ x[3],   8);
+
+               x[10] += x[15];   x[5]  = rotl32(x[5]  ^ x[10],  7);
+               x[11] += x[12];   x[6]  = rotl32(x[6]  ^ x[11],  7);
+               x[8]  += x[13];   x[7]  = rotl32(x[7]  ^ x[8],   7);
+               x[9]  += x[14];   x[4]  = rotl32(x[4]  ^ x[9],   7);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(x); i++)
+               out[i] = cpu_to_le32(x[i] + state[i]);
+
+       state[12]++;
+}
+EXPORT_SYMBOL(chacha20_block);