]> Pileus Git - ~andy/crypt/blob - scrypt.c
Add some initial code
[~andy/crypt] / scrypt.c
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "util.h"
6 #include "sha2.h"
7 #include "scrypt.h"
8
9 /**
10  * Name  RFC    Description
11  * pass  P      Passphrase, an octet string.
12  * salt  S      Salt, an octet string.
13  * cost  N      CPU/Memory cost parameter
14  * bs    r      Block size parameter.
15  * par   p      Parallelization parameter
16  * len?  dkLen  Intended output length
17  * in    B      Input data
18  * out   B'     Output data
19  */
20
21 /* Types */
22 typedef void hash_t(uint8_t *out, const uint8_t *in, int len);
23
24 /* Helpers */
25 #if 0
26 static int mod(uint8_t out[64], uint8_t in[64])
27 {
28 }
29
30 static void copy(uint8_t out[64], uint8_t in[64])
31 {
32 }
33
34 static void xor(uint8_t out[64], uint8_t a[64], uint8_t b[64])
35 {
36 }
37 #endif
38
39 /* HMAC */
40 static void hmac_gen(hash_t hash,
41                 uint8_t *out, int nout,
42                 const uint8_t *key, int nkey,
43                 const uint8_t *msg, int nmsg)
44 {
45         uint8_t *fix  = alloc0(nout);
46         uint8_t *ipad = alloc0(nout+nmsg);
47         uint8_t *opad = alloc0(nout+nout);
48
49         /* Fixup key */
50         if (nkey > nout)
51                 hash(fix, key, nkey);
52         else
53                 memcpy(fix, key, nkey);
54
55         /* Create pad strings */
56         for (int i = 0; i < nout; i++) {
57                 opad[i] = 0x5c ^ fix[i];
58                 ipad[i] = 0x36 ^ fix[i];
59         }
60
61         /* Run hashes - hash(o+hash(i+msg)) */
62         memcpy(ipad+nout, msg, nmsg);
63         hash(opad+nout, ipad, nout+nmsg);
64         hash(out, opad, nout+nout);
65
66         /* Cleanup */
67         free(fix);
68         free(opad);
69         free(ipad);
70 }
71
72 /* PBKDF2 */
73 static void pbkdf2_gen(uint8_t *out, int nout,
74                 const uint8_t *pass, int npass,
75                 const uint8_t *salt, int nsalt,
76                 int iter)
77 {
78         int      nbuf = nsalt + 4;
79         uint8_t *buf  = alloc0(nbuf);
80         memcpy(buf, salt, nsalt);
81
82         const int nptr = 256/8;
83
84         for (int i = 0; i < nout/nptr; i++) {
85                 uint8_t *ptr = &out[i*nptr];
86
87                 buf[nsalt+0] = ((i+1) & 0xFF000000) >> 030;
88                 buf[nsalt+1] = ((i+1) & 0x00FF0000) >> 020;
89                 buf[nsalt+2] = ((i+1) & 0x0000FF00) >> 010;
90                 buf[nsalt+3] = ((i+1) & 0x000000FF) >> 000;
91
92                 hmac_gen(sha256_hash, ptr, nptr, pass, npass, buf, nbuf);
93                 for (int j = 1; j < iter; j++)
94                         hmac_gen(sha256_hash, ptr, nptr, pass, npass, ptr, nptr);
95         }
96
97         free(buf);
98 }
99
100 static void pbkdf2_gen_str(uint8_t *out, int nout,
101                 const char *pass, const char *salt, int iter)
102 {
103         pbkdf2_gen(out, nout,
104                 (const uint8_t *)pass, strlen(pass),
105                 (const uint8_t *)salt, strlen(salt), iter);
106 }
107
108 /* Salsa20/8 */
109 static void salsa(uint8_t out[64], uint8_t in[64])
110 {
111 }
112
113 /* scrypt */
114 #if 0
115 static void block_mix(uint8_t *out[64], uint8_t *in[64], int bs)
116 {
117         // xor each block with the last block
118         // alternat first/second half for result
119
120         uint8_t tmp[64]
121         for (int i = 0; i < 2*r; i++) {
122                 int o = bs*(i%2) + (i/2);
123                 xor(tmp, in[2*r - 1], in[i]);
124                 salsa(out[o], tmp);
125         }
126 }
127
128 static void ro_mix(uint8_t *out[128], uint8_t *in[128], int cost, int bs)
129 {
130         // generate vector of size cost
131         // randomly collapse vector as output
132
133         uint8_t *state[64];
134         uint8_t *mixed[64];
135         uint8_t *tmp[64];
136
137         copy(state, in);
138
139         for (i = 0; i < cost; i++) {
140                 copy(mixed[i], state);
141                 block_mix(state, state);
142         }
143
144         for (i = 0; i < cost; i++) {
145                 int j = mod(state, cost);
146                 xor(tmp, state, mixed[j]);
147                 block_mix(state, tmp);
148         }
149
150         copy(out, state);
151 }
152
153 static void scrypt_run(uint8_t out[64],
154                 char *pass, char *salt,
155                 int cost, int bs, int par, int len)
156 {
157         // hash pass/salt into large buffer
158         // mix each buffer (in parallel)
159         // combine bubers into output
160
161         sha256_hmac(buf, pass, salt, 1, par * 128 * bs);
162
163         for (i = 0; i < par; i++)
164                 buf[i] = ro_mix(buf[i], cost, bs);
165
166         sha256_hmac(out, pass, buf, 1, len);
167 }
168 #endif
169
170 /* Entry point */
171 void scrypt_hash(uint8_t *in, uint8_t *sum)
172 {
173         *sum = 0;
174 }
175
176 /* Tests */
177 #if 0
178 static void test_script(void)
179 {
180         /* Parameters */
181         const int   cost = 1024;
182         const int   bs   = 1;
183         const int   par  = 1;
184         const int   len  = 32;
185
186         /* Input data */
187         const char *pass = "hello";
188         const char *salt = "world";
189
190         /* Output data */
191         static uint8_t out[32];
192
193         /* Run the hash */
194         scrypt_hash(out, pass, salt, par, bs, len);
195
196         /* Print output */
197 }
198 #endif
199
200 static void test_keygen(void)
201 {
202         const uint8_t truth0[] = {
203                 0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f,
204                 0xec, 0x16, 0x91, 0xc2, 0x25, 0x44, 0xb6, 0x05,
205                 0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65,
206                 0xe6, 0x8b, 0x9d, 0x57, 0xc2, 0x0d, 0xac, 0xbc,
207                 0x49, 0xca, 0x9c, 0xcc, 0xf1, 0x79, 0xb6, 0x45,
208                 0x99, 0x16, 0x64, 0xb3, 0x9d, 0x77, 0xef, 0x31,
209                 0x7c, 0x71, 0xb8, 0x45, 0xb1, 0xe3, 0x0b, 0xd5,
210                 0x09, 0x11, 0x20, 0x41, 0xd3, 0xa1, 0x97, 0x83,
211         };
212
213         const uint8_t truth1[] = {
214                 0x4d, 0xdc, 0xd8, 0xf6, 0x0b, 0x98, 0xbe, 0x21,
215                 0x83, 0x0c, 0xee, 0x5e, 0xf2, 0x27, 0x01, 0xf9,
216                 0x64, 0x1a, 0x44, 0x18, 0xd0, 0x4c, 0x04, 0x14,
217                 0xae, 0xff, 0x08, 0x87, 0x6b, 0x34, 0xab, 0x56,
218                 0xa1, 0xd4, 0x25, 0xa1, 0x22, 0x58, 0x33, 0x54,
219                 0x9a, 0xdb, 0x84, 0x1b, 0x51, 0xc9, 0xb3, 0x17,
220                 0x6a, 0x27, 0x2b, 0xde, 0xbb, 0xa1, 0xd0, 0x78,
221                 0x47, 0x8f, 0x62, 0xb3, 0x97, 0xf3, 0x3c, 0x8d,
222         };
223
224         uint8_t out0[64] = {};
225         uint8_t out1[64] = {};
226
227         //             output     password    salt    iters
228         pbkdf2_gen_str(out0, 64,  "passwd",   "salt", 1);
229         //pbkdf2_gen_str(out1, 64,  "Password", "NaCl", 80000);
230
231         hexdump("\nTest #1", NULL, truth0, 64);
232         hexdump("",          NULL, out0,   64);
233
234         hexdump("\nTest #2", NULL, truth1, 64);
235         hexdump("",          NULL, out1,   64);
236
237         (void)salsa;
238         (void)pbkdf2_gen;
239         (void)hmac_gen;
240 }
241
242 void scrypt_test(void)
243 {
244         test_keygen();
245 }