Rizin
unix-like reverse engineering framework and cli tools
crypto_serpent_algo.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2017 NicsTr <nicolas.bordes@grenoble-inp.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include "crypto_serpent_algo.h"
5 #include <rz_util/rz_assert.h>
6 
7 static const ut8 S[][16] = {
8  { 3, 8, 15, 1, 10, 6, 5, 11, 14, 13, 4, 2, 7, 0, 9, 12 }, /* S0: */
9  { 15, 12, 2, 7, 9, 0, 5, 10, 1, 11, 14, 8, 6, 13, 3, 4 }, /* S1: */
10  { 8, 6, 7, 9, 3, 12, 10, 15, 13, 1, 14, 4, 0, 11, 5, 2 }, /* S2: */
11  { 0, 15, 11, 8, 12, 9, 6, 3, 13, 1, 2, 4, 10, 7, 5, 14 }, /* S3: */
12  { 1, 15, 8, 3, 12, 0, 11, 6, 2, 5, 4, 10, 9, 14, 7, 13 }, /* S4: */
13  { 15, 5, 2, 11, 4, 10, 9, 12, 0, 3, 14, 8, 13, 6, 7, 1 }, /* S5: */
14  { 7, 2, 12, 5, 8, 4, 6, 11, 14, 9, 1, 15, 13, 3, 10, 0 }, /* S6: */
15  { 1, 13, 15, 0, 14, 8, 2, 11, 7, 4, 12, 10, 9, 3, 5, 6 }, /* S7: */
16 };
17 
18 static const ut8 Sinv[][16] = {
19  { 13, 3, 11, 0, 10, 6, 5, 12, 1, 14, 4, 7, 15, 9, 8, 2 }, /* InvS0: */
20  { 5, 8, 2, 14, 15, 6, 12, 3, 11, 4, 7, 9, 1, 13, 10, 0 }, /* InvS1: */
21  { 12, 9, 15, 4, 11, 14, 1, 2, 0, 3, 6, 13, 5, 8, 10, 7 }, /* InvS2: */
22  { 0, 9, 10, 7, 11, 14, 6, 13, 3, 5, 12, 2, 4, 8, 15, 1 }, /* InvS3: */
23  { 5, 0, 8, 3, 10, 9, 7, 14, 2, 12, 11, 6, 4, 15, 13, 1 }, /* InvS4: */
24  { 8, 15, 2, 9, 4, 1, 13, 14, 11, 6, 5, 3, 7, 12, 10, 0 }, /* InvS5: */
25  { 15, 10, 1, 13, 5, 3, 6, 0, 4, 9, 14, 7, 2, 12, 8, 11 }, /* InvS6: */
26  { 3, 0, 6, 13, 9, 14, 15, 8, 5, 12, 11, 7, 10, 1, 4, 2 }, /* InvS7: */
27 };
28 
29 static const ut8 IPTable[] = {
30  0, 32, 64, 96, 1, 33, 65, 97, 2, 34, 66, 98, 3, 35, 67, 99,
31  4, 36, 68, 100, 5, 37, 69, 101, 6, 38, 70, 102, 7, 39, 71, 103,
32  8, 40, 72, 104, 9, 41, 73, 105, 10, 42, 74, 106, 11, 43, 75, 107,
33  12, 44, 76, 108, 13, 45, 77, 109, 14, 46, 78, 110, 15, 47, 79, 111,
34  16, 48, 80, 112, 17, 49, 81, 113, 18, 50, 82, 114, 19, 51, 83, 115,
35  20, 52, 84, 116, 21, 53, 85, 117, 22, 54, 86, 118, 23, 55, 87, 119,
36  24, 56, 88, 120, 25, 57, 89, 121, 26, 58, 90, 122, 27, 59, 91, 123,
37  28, 60, 92, 124, 29, 61, 93, 125, 30, 62, 94, 126, 31, 63, 95, 127
38 };
39 
40 static const ut8 FPTable[] = {
41  0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60,
42  64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124,
43  1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61,
44  65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125,
45  2, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62,
46  66, 70, 74, 78, 82, 86, 90, 94, 98, 102, 106, 110, 114, 118, 122, 126,
47  3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63,
48  67, 71, 75, 79, 83, 87, 91, 95, 99, 103, 107, 111, 115, 119, 123, 127
49 };
50 
51 static inline void rotr(ut32 *x, int s) {
52  *x = (*x >> s) | (*x << (32 - s));
53 }
54 
55 static inline void rotl(ut32 *x, int s) {
56  *x = (*x << s) | (*x >> (32 - s));
57 }
58 
59 /* Apply SBox to the four least significant bits */
60 static inline ut8 apply_sbox(int si, ut8 x) {
61  x = S[si][x & 0xf];
62  return x;
63 }
64 /* Apply SBox to the four least significant bits */
65 static inline ut8 apply_sbox_inv(int si, ut8 x) {
66  x = Sinv[si][x & 0xf];
67  return x;
68 }
69 
70 static inline ut8 get_bit(int i, ut32 input) {
71  rz_return_val_if_fail(i < 32, 0);
72  return (input >> i) & 1;
73 }
74 
76  int index;
77  int i;
78  for (i = 0; i < DW_BY_BLOCK * 32; i++) {
79  index = IPTable[i];
80  out[i / 32] ^= (-(ut32)get_bit(index % 32, in[index / 32]) ^ out[i / 32]) & (1 << (i & 0x1f));
81  }
82 }
83 
85  int index;
86  int i;
87  for (i = 0; i < DW_BY_BLOCK * 32; i++) {
88  index = FPTable[i];
89  out[i / 32] ^= (-(ut32)get_bit(index % 32, in[index / 32]) ^ out[i / 32]) & (1 << (i & 0x1f));
90  }
91 }
92 
94  rz_return_if_fail((st->key_size == 128) || (st->key_size == 192) || (st->key_size == 256));
95 
96  ut32 tmpkeys[DW_BY_BLOCK * NB_SUBKEYS + DW_BY_USERKEY] = { 0 };
97  const ut32 phi = 0x9e3779b9;
98  int si;
99  ut8 in, out;
100  int i, j, l;
101 
102  for (i = 0; i < st->key_size / 32; i++) {
103  tmpkeys[i] = st->key[i];
104  }
105 
106  // Padding key
107  if (st->key_size != 256) {
108  tmpkeys[st->key_size / 32] = 1;
109  }
110 
112  tmpkeys[i] = tmpkeys[i - 8] ^ tmpkeys[i - 5] ^ tmpkeys[i - 3] ^ tmpkeys[i - 1] ^ phi ^ (i - 8);
113  rotl(tmpkeys + i, 11);
114  }
115 
116  // Applying sbox for subkey i
117  for (i = 0; i < NB_SUBKEYS; i++) {
118  si = (32 + 3 - i) % 8;
119 
120  // Iterates over all nibbles of the subkey i
121  for (j = 0; j < NIBBLES_BY_SUBKEY; j++) {
122  in = get_bit(j, tmpkeys[0 + DW_BY_BLOCK * i + DW_BY_USERKEY]) | get_bit(j, tmpkeys[1 + DW_BY_BLOCK * i + DW_BY_USERKEY]) << 1 | get_bit(j, tmpkeys[2 + DW_BY_BLOCK * i + DW_BY_USERKEY]) << 2 | get_bit(j, tmpkeys[3 + DW_BY_BLOCK * i + DW_BY_USERKEY]) << 3;
123  out = apply_sbox(si, in);
124  for (l = 0; l < DW_BY_BLOCK; l++) {
125  subkeys[l + DW_BY_BLOCK * i] |= get_bit(l, (ut32)out) << j;
126  }
127  }
128  }
129 
130  // Apply IP on every subkey
131  for (i = 0; i < NB_SUBKEYS; i++) {
132  apply_IP(&subkeys[i * DW_BY_BLOCK], &tmpkeys[DW_BY_USERKEY + i * DW_BY_BLOCK]);
133  }
134 
135  memcpy(subkeys, tmpkeys + DW_BY_USERKEY, 132 * sizeof(ut32));
136 }
137 
138 void apply_xor(ut32 block[DW_BY_BLOCK], ut32 subkey[DW_BY_BLOCK]) {
139  int i;
140  for (i = 0; i < DW_BY_BLOCK; i++) {
141  block[i] ^= subkey[i];
142  }
143 }
144 
146  ut32 tmp_block[DW_BY_BLOCK] = { 0 };
147  apply_FP(block, tmp_block);
148  rotl(tmp_block + 0, 13);
149  rotl(tmp_block + 2, 3);
150  tmp_block[1] ^= tmp_block[0] ^ tmp_block[2];
151  tmp_block[3] ^= tmp_block[2] ^ (tmp_block[0] << 3);
152  rotl(tmp_block + 1, 1);
153  rotl(tmp_block + 3, 7);
154  tmp_block[0] ^= tmp_block[1] ^ tmp_block[3];
155  tmp_block[2] ^= tmp_block[3] ^ (tmp_block[1] << 7);
156  rotl(tmp_block + 0, 5);
157  rotl(tmp_block + 2, 22);
158  apply_IP(tmp_block, block);
159 }
160 
162  ut32 tmp_block[DW_BY_BLOCK] = { 0 };
163  apply_FP(block, tmp_block);
164  rotr(tmp_block + 0, 5);
165  rotr(tmp_block + 2, 22);
166  tmp_block[2] ^= tmp_block[3] ^ (tmp_block[1] << 7);
167  tmp_block[0] ^= tmp_block[1] ^ tmp_block[3];
168  rotr(tmp_block + 3, 7);
169  rotr(tmp_block + 1, 1);
170  tmp_block[3] ^= tmp_block[2] ^ (tmp_block[0] << 3);
171  tmp_block[1] ^= tmp_block[0] ^ tmp_block[2];
172  rotr(tmp_block + 2, 3);
173  rotr(tmp_block + 0, 13);
174  apply_IP(tmp_block, block);
175 }
176 
177 void apply_round(int round, ut32 block[DW_BY_BLOCK],
178  ut32 subkeys[DW_BY_BLOCK * NB_SUBKEYS]) {
179  int i, j;
180 
181  apply_xor(block, subkeys + 4 * round);
182 
183  for (i = 0; i < DW_BY_BLOCK; i++) {
184  ut32 res = 0;
185  for (j = 0; j < 8; j++) {
186  res |= apply_sbox(round % 8, (block[i] >> 4 * j) & 0xf) << 4 * j;
187  }
188  block[i] = res;
189  }
190 
191  if (round == NB_ROUNDS - 1) {
192  apply_xor(block, subkeys + 4 * (round + 1));
193  } else {
194  apply_permut(block);
195  }
196 }
197 
198 void apply_round_inv(int round, ut32 block[DW_BY_BLOCK],
199  ut32 subkeys[DW_BY_BLOCK * NB_SUBKEYS]) {
200  if (round == NB_ROUNDS - 1) {
201  apply_xor(block, subkeys + 4 * (round + 1));
202  } else {
203  apply_permut_inv(block);
204  }
205 
206  int i, j;
207  ut32 res;
208 
209  for (i = 0; i < DW_BY_BLOCK; i++) {
210  res = 0;
211  for (j = 0; j < 8; j++) {
212  res |= apply_sbox_inv(round % 8, (block[i] >> 4 * j) & 0xf) << 4 * j;
213  }
214  block[i] = res;
215  }
216 
217  apply_xor(block, subkeys + 4 * round);
218 }
219 
221  ut32 out[DW_BY_BLOCK]) {
222  int i;
223  ut32 subkeys[DW_BY_BLOCK * NB_SUBKEYS] = { 0 };
224  ut32 tmp_block[DW_BY_BLOCK] = { 0 };
225 
226  serpent_keyschedule(st, subkeys);
227 
228  apply_IP(in, tmp_block);
229  for (i = 0; i < NB_ROUNDS; i++) {
230  apply_round(i, tmp_block, subkeys);
231  }
232  apply_FP(tmp_block, out);
233 }
234 
236  ut32 out[DW_BY_BLOCK]) {
237  int i;
238  ut32 subkeys[DW_BY_BLOCK * NB_SUBKEYS] = { 0 };
239  ut32 tmp_block[DW_BY_BLOCK] = { 0 };
240 
241  serpent_keyschedule(st, subkeys);
242 
243  apply_IP(in, tmp_block);
244  for (i = NB_ROUNDS - 1; i >= 0; i--) {
245  apply_round_inv(i, tmp_block, subkeys);
246  }
247  apply_FP(tmp_block, out);
248 }
si
lzma_index ** i
Definition: index.h:629
const lzma_allocator const uint8_t * in
Definition: block.h:527
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
static const ut8 S[][16]
void apply_round_inv(int round, ut32 block[DW_BY_BLOCK], ut32 subkeys[DW_BY_BLOCK *NB_SUBKEYS])
static ut8 apply_sbox_inv(int si, ut8 x)
void apply_round(int round, ut32 block[DW_BY_BLOCK], ut32 subkeys[DW_BY_BLOCK *NB_SUBKEYS])
void apply_IP(ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK])
static ut8 apply_sbox(int si, ut8 x)
void serpent_keyschedule(const serpent_state_t *st, ut32 subkeys[NB_SUBKEYS *DW_BY_BLOCK])
void serpent_decrypt(serpent_state_t *st, ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK])
static ut8 get_bit(int i, ut32 input)
static const ut8 IPTable[]
void apply_xor(ut32 block[DW_BY_BLOCK], ut32 subkey[DW_BY_BLOCK])
void apply_FP(ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK])
static const ut8 Sinv[][16]
static void rotl(ut32 *x, int s)
static const ut8 FPTable[]
void serpent_encrypt(serpent_state_t *st, ut32 in[DW_BY_BLOCK], ut32 out[DW_BY_BLOCK])
void apply_permut(ut32 block[DW_BY_BLOCK])
void apply_permut_inv(ut32 block[DW_BY_BLOCK])
static void rotr(ut32 *x, int s)
#define NB_SUBKEYS
#define NB_ROUNDS
#define DW_BY_BLOCK
#define DW_BY_USERKEY
#define NIBBLES_BY_SUBKEY
uint32_t ut32
uint8_t ut8
Definition: lh5801.h:11
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
int x
Definition: mipsasm.c:20
static RzSocket * s
Definition: rtr.c:28
#define rz_return_if_fail(expr)
Definition: rz_assert.h:100
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
static bool input(void *ud, zip_uint8_t *data, zip_uint64_t length)