1 /*
2  *   Copyright (c) 2015-2018, Andrew Romanenko <melanhit@gmail.com>
3  *   All rights reserved.
4  *
5  *   Redistribution and use in source and binary forms, with or without
6  *   modification, are permitted provided that the following conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above copyright notice, this
9  *      list of conditions and the following disclaimer.
10  *   2. Redistributions in binary form must reproduce the above copyright notice,
11  *      this list of conditions and the following disclaimer in the documentation
12  *      and/or other materials provided with the distribution.
13  *   3. Neither the name of the project nor the names of its contributors
14  *      may be used to endorse or promote products derived from this software
15  *      without specific prior written permission.
16  *
17  *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
18  *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21  *   ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  *   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  *   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <stdlib.h>
30 #include <stdint.h>
31 
32 #include "../akmos.h"
33 #include "../bits.h"
34 #include "../cipher.h"
35 
36 #include "threefish.h"
37 #include "threefish_mix.h"
38 
39 #define WORDS_256   AKMOS_THREEFISH_WORDS_256
40 #define ROUNDS_256  (72 / 8)
41 #define SKEYS_256   ((ROUNDS_256 * 2) + 1)
42 
akmos_threefish_256_setkey(akmos_cipher_algo_t * uctx,const uint8_t * key,size_t len)43 void akmos_threefish_256_setkey(akmos_cipher_algo_t *uctx,
44                                 const uint8_t *key,
45                                 size_t __attribute__((unused)) len)
46 {
47     akmos_threefish_256_t *ctx;
48     uint64_t *k, *S;
49     size_t i, j;
50 
51     ctx = &uctx->tf_256;
52 
53     k = ctx->k;
54 
55     for(i = 0; i < WORDS_256; i++, key += 8)
56         k[i] = PACK64BE(key);
57 
58     k[WORDS_256] = AKMOS_THREEFISH_C240;
59 
60     for(i = 0; i < WORDS_256; i++)
61         k[WORDS_256] ^= k[i];
62 
63     for(i = 0, S = ctx->S; i < SKEYS_256; i++, S += WORDS_256) {
64         for(j = 0; j < WORDS_256; j++)
65             S[j] = k[(i+j)%(WORDS_256+1)];
66 
67         S[WORDS_256-1] += i;
68     }
69 }
70 
akmos_threefish_256_encrypt(akmos_cipher_algo_t * uctx,const uint8_t * in_blk,uint8_t * out_blk)71 void akmos_threefish_256_encrypt(akmos_cipher_algo_t *uctx,
72                                  const uint8_t *in_blk,
73                                  uint8_t *out_blk)
74 {
75     akmos_threefish_256_t *ctx;
76     uint64_t s[WORDS_256], *S;
77     int i, j;
78 
79     ctx = &uctx->tf_256;
80 
81     for(i = 0; i < WORDS_256; i++, in_blk += 8)
82         s[i] = PACK64BE(in_blk);
83 
84     for(i = 0, S = ctx->S; i < ROUNDS_256; i++, S += WORDS_256) {
85         for(j = 0; j < WORDS_256; j++)
86             s[j] += S[j];
87 
88         threefish_256_emix(s, 14, 16, 52, 57);
89         threefish_256_emix(s, 23, 40,  5, 37);
90 
91         for(j = 0, S += WORDS_256; j < WORDS_256; j++)
92             s[j] += S[j];
93 
94         threefish_256_emix(s, 25, 33, 46, 12);
95         threefish_256_emix(s, 58, 22, 32, 32);
96     }
97 
98     for(i = 0; i < WORDS_256; i++, out_blk += 8)
99         UNPACK64BE(out_blk, s[i] + S[i]);
100 }
101 
akmos_threefish_256_decrypt(akmos_cipher_algo_t * uctx,const uint8_t * in_blk,uint8_t * out_blk)102 void akmos_threefish_256_decrypt(akmos_cipher_algo_t *uctx,
103                                  const uint8_t *in_blk,
104                                  uint8_t *out_blk)
105 {
106     akmos_threefish_256_t *ctx;
107     uint64_t s[WORDS_256], *S;
108     int i, j;
109 
110     ctx = &uctx->tf_256;
111 
112     for(i = 0; i < WORDS_256; i++, in_blk += 8)
113         s[i] = PACK64BE(in_blk);
114 
115     S = ctx->S + (WORDS_256 * (SKEYS_256 - 1));
116     for(i = 0; i < WORDS_256; i++)
117         s[i] -= S[i];
118 
119     for(i = ROUNDS_256; i > 0; i--) {
120         threefish_256_dmix(s, 32, 32, 58, 22);
121         threefish_256_dmix(s, 46, 12, 25, 33);
122 
123         for(j = 0, S -= WORDS_256; j < WORDS_256; j++)
124             s[j] -= S[j];
125 
126         threefish_256_dmix(s,  5, 37, 23, 40);
127         threefish_256_dmix(s, 52, 57, 14, 16);
128 
129         for(j = 0, S -= WORDS_256; j < WORDS_256; j++)
130             s[j] -= S[j];
131     }
132 
133     for(i = 0; i < WORDS_256; i++, out_blk += 8)
134         UNPACK64BE(out_blk, s[i]);
135 }
136