|
| 1 | +# crypt with sha2 scheme |
| 2 | +# %% draft implementation |
| 3 | +# %% sha512 only |
| 4 | + |
| 5 | +# Copyright © 2016 Aleksey Cherepanov <[email protected]> |
| 6 | +# Redistribution and use in source and binary forms, with or without |
| 7 | +# modification, are permitted. |
| 8 | + |
| 9 | +# http://www.akkadia.org/drepper/SHA-crypt.txt |
| 10 | + |
| 11 | +# Var.setup('be', args['size']) |
| 12 | + |
| 13 | +sha = load_hfun('sha512') |
| 14 | + |
| 15 | +# Algo |
| 16 | + |
| 17 | +key = input_key() |
| 18 | +salt = input_salt() |
| 19 | +rounds = input_rounds() |
| 20 | + |
| 21 | +key_length = bytes_length(key) |
| 22 | +salt_length = bytes_length(salt) |
| 23 | +# key_bit_length = get_bit_length(key) |
| 24 | + |
| 25 | +ks = bytes_concat(key, salt) |
| 26 | +ksk = bytes_concat(ks, key) |
| 27 | +b = invoke_hfun(sha, ksk) |
| 28 | + |
| 29 | +a = sha_init() |
| 30 | +ksa = bytes_concat(ks, b) |
| 31 | + |
| 32 | +# 11 |
| 33 | +# maximal password length is 125 |
| 34 | +# %% хорошо бы тут использовать другой тип |
| 35 | +c = new_var() |
| 36 | +c // key_length |
| 37 | +bb = new_bytes() |
| 38 | +bytes_assign(bb, ksa) |
| 39 | +cycle_while_begin('step11') |
| 40 | +cycle_while('step11', c > 0) |
| 41 | + |
| 42 | +if_condition('c1', c & 1) |
| 43 | +bytes_assign(bb, bytes_concat(bb, b)) |
| 44 | +if_else('c1') |
| 45 | +bytes_assign(bb, bytes_concat(bb, key)) |
| 46 | +if_end('c1') |
| 47 | + |
| 48 | +c // (c >> 1) |
| 49 | +cycle_end('step11') |
| 50 | + |
| 51 | +# 12 |
| 52 | +a = invoke_hfun(sha, bb) |
| 53 | + |
| 54 | +# %% not inclusive |
| 55 | +kkk = new_bytes() |
| 56 | +unused = cycle_range('step14', 0, key_length - 1, 1) |
| 57 | +bytes_assign(kkk, bytes_concat(kkk, key)) |
| 58 | +cycle_end('step14') |
| 59 | +dp = invoke_hfun(sha, kkk) |
| 60 | + |
| 61 | + |
| 62 | +# %%% я остановился тут |
| 63 | + |
| 64 | +p = fill_string(key_length, dp_string, dp_string_length) |
| 65 | +p_length = key_length |
| 66 | + |
| 67 | +# 18 |
| 68 | +ds = sha_init() |
| 69 | +# for i in range(16 + a[0]): |
| 70 | +# sha_update(ds, salt) |
| 71 | +# %% big endian? |
| 72 | +# %% not inclusive |
| 73 | +c = cycle_range('setup_s', 0, new_const(16) + ((a[0] & (0xff << 56)) >> 56) - 1, 1) |
| 74 | +sha_update(ds, salt, salt_length) |
| 75 | +cycle_end('setup_s') |
| 76 | +ds = sha_final(ds) |
| 77 | + |
| 78 | +ds_string = digest_to_string(ds) |
| 79 | +ds_string_length = 8 * 8 |
| 80 | + |
| 81 | +s = fill_string(salt_length, ds_string, ds_string_length) |
| 82 | +s_length = salt_length |
| 83 | + |
| 84 | +# 21 |
| 85 | + |
| 86 | +# # pseudo code |
| 87 | +# for r in range(rounds - 1): |
| 88 | +# c = sha_init() |
| 89 | +# sha_update(c, p if r & 1 else ac) |
| 90 | +# if r % 3 != 0: sha_update(c, s) |
| 91 | +# if r % 7 != 0: sha_update(c, p) |
| 92 | +# sha_update(c, ac if r & 1 else p) |
| 93 | +# c = sha_final(c) |
| 94 | +# ac = c |
| 95 | + |
| 96 | +# Notice that computation of some blocks maybe lifted from the loop |
| 97 | + |
| 98 | +# Statistics of sequences for first 5k rounds: |
| 99 | +# perl -e 'for (0 .. 5000) { if ($_ & 1) { print " ac," } else { print " p," } print " s," if $_ % 3; print " p," if $_ % 7; if ($_ & 1) { print " p" } else { print " ac" } print "\n" }' | sort | uniq -c |
| 100 | +# 119 ac, p |
| 101 | +# 714 ac, p, p |
| 102 | +# 238 ac, s, p |
| 103 | +# 1429 ac, s, p, p |
| 104 | +# 120 p, ac |
| 105 | +# 714 p, p, ac |
| 106 | +# 238 p, s, ac |
| 107 | +# 1429 p, s, p, ac |
| 108 | +# =5001, 1667 ps and psp may be brought upper |
| 109 | + |
| 110 | +# The full cycle is 2 * 3 * 7 == 42 rounds, having such unroll it is |
| 111 | +# possible to avoid most "if"s in the loop. There are 21 variants |
| 112 | +# Without ac/p. |
| 113 | +# %% Right? |
| 114 | + |
| 115 | +# %% It'd be nice to do such optimization automatically... |
| 116 | + |
| 117 | +# # %% add 0x80 and compute lengths |
| 118 | +# # Only ac is variable. Other parts may be extracted: |
| 119 | +# pp = string_concat(p, p) |
| 120 | +# sp = string_concat(s, p) |
| 121 | +# spp = string_concat(s, p, p) |
| 122 | +# ps = string_concat(p, s) |
| 123 | +# psp = string_concat(p, s, p) |
| 124 | +# pp = string_to_ints(pp) |
| 125 | +# sp = string_to_ints(sp) |
| 126 | +# spp = string_to_ints(spp) |
| 127 | +# ps = string_to_ints(ps) |
| 128 | +# psp = string_to_ints(psp) |
| 129 | + |
| 130 | +# %% It is possible to reduce memory footprint storing pp in spp, and |
| 131 | +# sp in psp; also it is possible to store ps inside psp, but it may |
| 132 | +# be needed to pass lengths then |
| 133 | + |
| 134 | +# for r in range(rounds - 1): |
| 135 | +# c = sha_init() |
| 136 | +# if r & 1: |
| 137 | +# if r % 3 and r % 7: |
| 138 | +# sha_update(c, psp) |
| 139 | +# elif r % 7: |
| 140 | +# sha_update(c, pp) |
| 141 | +# elif r % 3: |
| 142 | +# sha_update(c, ps) |
| 143 | +# else: |
| 144 | +# sha_update(c, p) |
| 145 | +# sha_update(c, ac) |
| 146 | +# else: |
| 147 | +# sha_update(c, ac) |
| 148 | +# if r % 3 and r % 7: |
| 149 | +# sha_update(c, spp) |
| 150 | +# elif r % 7: |
| 151 | +# sha_update(c, pp) |
| 152 | +# elif r % 3: |
| 153 | +# sha_update(c, sp) |
| 154 | +# else: |
| 155 | +# sha_update(c, p) |
| 156 | +# c = sha_final(c) |
| 157 | +# ac = c |
| 158 | + |
| 159 | +# r = cycle_range('main', 0, rounds, 1) |
| 160 | +# # %% Compute 8? |
| 161 | +# c_array = [Var() for i in range(8)] |
| 162 | +# # ints_concat is "macro", free |
| 163 | +# f = lambda x, y: sha_ints(ints_concat(x, y)) |
| 164 | +# c = iff(r & 1, |
| 165 | +# # %% lift computation of some blocks from the cycle |
| 166 | +# iff(r % 3 and r % 7, f(psp, c), |
| 167 | +# iff(r % 7, f(pp, c), |
| 168 | +# iff(r % 3, f(ps, c), |
| 169 | +# f(p, c)))), |
| 170 | +# iff(r % 3 and r % 7, f(c, spp), |
| 171 | +# iff(r % 7, f(c, pp), |
| 172 | +# iff(r % 3, f(c, sp), |
| 173 | +# f(c, p))))) |
| 174 | +# for i, v in enumerate(c): |
| 175 | +# c_array[i] // c[i] |
| 176 | +# cycle_end('main') |
| 177 | + |
| 178 | +ac = a |
| 179 | + |
| 180 | +# %% not inclusive |
| 181 | +r = cycle_range('main', 0, rounds - 1, 1) |
| 182 | +c = sha_init() |
| 183 | +# print_var(r) |
| 184 | +# print_digest(ac) |
| 185 | +ac_string = digest_to_string(ac) |
| 186 | +ac_string_length = 8 * 8 |
| 187 | +if_condition('r1', r & 1) |
| 188 | +sha_update(c, p, p_length) |
| 189 | +if_else('r1') |
| 190 | +sha_update(c, ac_string, ac_string_length) |
| 191 | +if_end('r1') |
| 192 | +if_condition('r3', r % 3) |
| 193 | +sha_update(c, s, s_length) |
| 194 | +if_end('r3') |
| 195 | +if_condition('r7', r % 7) |
| 196 | +sha_update(c, p, p_length) |
| 197 | +if_end('r7') |
| 198 | +if_condition('r2', r & 1) |
| 199 | +sha_update(c, ac_string, ac_string_length) |
| 200 | +if_else('r2') |
| 201 | +sha_update(c, p, p_length) |
| 202 | +if_end('r2') |
| 203 | +# мы затираем 'a' |
| 204 | +# %% memory leak? |
| 205 | +ac // sha_final(c) |
| 206 | +cycle_end('main') |
| 207 | + |
| 208 | +# %% avoid hardcoded value, how? |
| 209 | +for i in range(8): |
| 210 | + output(ac[i]) |
0 commit comments