Merge tag 'v5.15.57' into rpi-5.15.y
[platform/kernel/linux-rpi.git] / drivers / usb / host / dwc_common_port / dwc_dh.c
1 /* =========================================================================
2  * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_dh.c $
3  * $Revision: #3 $
4  * $Date: 2010/09/28 $
5  * $Change: 1596182 $
6  *
7  * Synopsys Portability Library Software and documentation
8  * (hereinafter, "Software") is an Unsupported proprietary work of
9  * Synopsys, Inc. unless otherwise expressly agreed to in writing
10  * between Synopsys and you.
11  *
12  * The Software IS NOT an item of Licensed Software or Licensed Product
13  * under any End User Software License Agreement or Agreement for
14  * Licensed Product with Synopsys or any supplement thereto. You are
15  * permitted to use and redistribute this Software in source and binary
16  * forms, with or without modification, provided that redistributions
17  * of source code must retain this notice. You may not view, use,
18  * disclose, copy or distribute this file or any information contained
19  * herein except pursuant to this license grant from Synopsys. If you
20  * do not agree with this notice, including the disclaimer below, then
21  * you are not authorized to use the Software.
22  *
23  * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS"
24  * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL
27  * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
31  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34  * DAMAGE.
35  * ========================================================================= */
36 #ifdef DWC_CRYPTOLIB
37
38 #ifndef CONFIG_MACH_IPMATE
39
40 #include "dwc_dh.h"
41 #include "dwc_modpow.h"
42
43 #ifdef DEBUG
44 /* This function prints out a buffer in the format described in the Association
45  * Model specification. */
46 static void dh_dump(char *str, void *_num, int len)
47 {
48         uint8_t *num = _num;
49         int i;
50         DWC_PRINTF("%s\n", str);
51         for (i = 0; i < len; i ++) {
52                 DWC_PRINTF("%02x", num[i]);
53                 if (((i + 1) % 2) == 0) DWC_PRINTF(" ");
54                 if (((i + 1) % 26) == 0) DWC_PRINTF("\n");
55         }
56
57         DWC_PRINTF("\n");
58 }
59 #else
60 #define dh_dump(_x...) do {; } while(0)
61 #endif
62
63 /* Constant g value */
64 static __u32 dh_g[] = {
65         0x02000000,
66 };
67
68 /* Constant p value */
69 static __u32 dh_p[] = {
70         0xFFFFFFFF, 0xFFFFFFFF, 0xA2DA0FC9, 0x34C26821, 0x8B62C6C4, 0xD11CDC80, 0x084E0229, 0x74CC678A,
71         0xA6BE0B02, 0x229B133B, 0x79084A51, 0xDD04348E, 0xB31995EF, 0x1B433ACD, 0x6D0A2B30, 0x37145FF2,
72         0x6D35E14F, 0x45C2516D, 0x76B585E4, 0xC67E5E62, 0xE9424CF4, 0x6BED37A6, 0xB65CFF0B, 0xEDB706F4,
73         0xFB6B38EE, 0xA59F895A, 0x11249FAE, 0xE61F4B7C, 0x51662849, 0x3D5BE4EC, 0xB87C00C2, 0x05BF63A1,
74         0x3648DA98, 0x9AD3551C, 0xA83F1669, 0x5FCF24FD, 0x235D6583, 0x96ADA3DC, 0x56F3621C, 0xBB528520,
75         0x0729D59E, 0x6D969670, 0x4E350C67, 0x0498BC4A, 0x086C74F1, 0x7C2118CA, 0x465E9032, 0x3BCE362E,
76         0x2C779EE3, 0x03860E18, 0xA283279B, 0x8FA207EC, 0xF05DC5B5, 0xC9524C6F, 0xF6CB2BDE, 0x18175895,
77         0x7C499539, 0xE56A95EA, 0x1826D215, 0x1005FA98, 0x5A8E7215, 0x2DC4AA8A, 0x0D1733AD, 0x337A5004,
78         0xAB2155A8, 0x64BA1CDF, 0x0485FBEC, 0x0AEFDB58, 0x5771EA8A, 0x7D0C065D, 0x850F97B3, 0xC7E4E1A6,
79         0x8CAEF5AB, 0xD73309DB, 0xE0948C1E, 0x9D61254A, 0x26D2E3CE, 0x6BEED21A, 0x06FA2FF1, 0x64088AD9,
80         0x730276D8, 0x646AC83E, 0x182B1F52, 0x0C207B17, 0x5717E1BB, 0x6C5D617A, 0xC0880977, 0xE246D9BA,
81         0xA04FE208, 0x31ABE574, 0xFC5BDB43, 0x8E10FDE0, 0x20D1824B, 0xCAD23AA9, 0xFFFFFFFF, 0xFFFFFFFF,
82 };
83
84 static void dh_swap_bytes(void *_in, void *_out, uint32_t len)
85 {
86         uint8_t *in = _in;
87         uint8_t *out = _out;
88         int i;
89         for (i=0; i<len; i++) {
90                 out[i] = in[len-1-i];
91         }
92 }
93
94 /* Computes the modular exponentiation (num^exp % mod).  num, exp, and mod are
95  * big endian numbers of size len, in bytes.  Each len value must be a multiple
96  * of 4. */
97 int dwc_dh_modpow(void *mem_ctx, void *num, uint32_t num_len,
98                   void *exp, uint32_t exp_len,
99                   void *mod, uint32_t mod_len,
100                   void *out)
101 {
102         /* modpow() takes little endian numbers.  AM uses big-endian.  This
103          * function swaps bytes of numbers before passing onto modpow. */
104
105         int retval = 0;
106         uint32_t *result;
107
108         uint32_t *bignum_num = dwc_alloc(mem_ctx, num_len + 4);
109         uint32_t *bignum_exp = dwc_alloc(mem_ctx, exp_len + 4);
110         uint32_t *bignum_mod = dwc_alloc(mem_ctx, mod_len + 4);
111
112         dh_swap_bytes(num, &bignum_num[1], num_len);
113         bignum_num[0] = num_len / 4;
114
115         dh_swap_bytes(exp, &bignum_exp[1], exp_len);
116         bignum_exp[0] = exp_len / 4;
117
118         dh_swap_bytes(mod, &bignum_mod[1], mod_len);
119         bignum_mod[0] = mod_len / 4;
120
121         result = dwc_modpow(mem_ctx, bignum_num, bignum_exp, bignum_mod);
122         if (!result) {
123                 retval = -1;
124                 goto dh_modpow_nomem;
125         }
126
127         dh_swap_bytes(&result[1], out, result[0] * 4);
128         dwc_free(mem_ctx, result);
129
130  dh_modpow_nomem:
131         dwc_free(mem_ctx, bignum_num);
132         dwc_free(mem_ctx, bignum_exp);
133         dwc_free(mem_ctx, bignum_mod);
134         return retval;
135 }
136
137
138 int dwc_dh_pk(void *mem_ctx, uint8_t nd, uint8_t *exp, uint8_t *pk, uint8_t *hash)
139 {
140         int retval;
141         uint8_t m3[385];
142
143 #ifndef DH_TEST_VECTORS
144         DWC_RANDOM_BYTES(exp, 32);
145 #endif
146
147         /* Compute the pkd */
148         if ((retval = dwc_dh_modpow(mem_ctx, dh_g, 4,
149                                     exp, 32,
150                                     dh_p, 384, pk))) {
151                 return retval;
152         }
153
154         m3[384] = nd;
155         DWC_MEMCPY(&m3[0], pk, 384);
156         DWC_SHA256(m3, 385, hash);
157
158         dh_dump("PK", pk, 384);
159         dh_dump("SHA-256(M3)", hash, 32);
160         return 0;
161 }
162
163 int dwc_dh_derive_keys(void *mem_ctx, uint8_t nd, uint8_t *pkh, uint8_t *pkd,
164                        uint8_t *exp, int is_host,
165                        char *dd, uint8_t *ck, uint8_t *kdk)
166 {
167         int retval;
168         uint8_t mv[784];
169         uint8_t sha_result[32];
170         uint8_t dhkey[384];
171         uint8_t shared_secret[384];
172         char *message;
173         uint32_t vd;
174
175         uint8_t *pk;
176
177         if (is_host) {
178                 pk = pkd;
179         }
180         else {
181                 pk = pkh;
182         }
183
184         if ((retval = dwc_dh_modpow(mem_ctx, pk, 384,
185                                     exp, 32,
186                                     dh_p, 384, shared_secret))) {
187                 return retval;
188         }
189         dh_dump("Shared Secret", shared_secret, 384);
190
191         DWC_SHA256(shared_secret, 384, dhkey);
192         dh_dump("DHKEY", dhkey, 384);
193
194         DWC_MEMCPY(&mv[0], pkd, 384);
195         DWC_MEMCPY(&mv[384], pkh, 384);
196         DWC_MEMCPY(&mv[768], "displayed digest", 16);
197         dh_dump("MV", mv, 784);
198
199         DWC_SHA256(mv, 784, sha_result);
200         dh_dump("SHA-256(MV)", sha_result, 32);
201         dh_dump("First 32-bits of SHA-256(MV)", sha_result, 4);
202
203         dh_swap_bytes(sha_result, &vd, 4);
204 #ifdef DEBUG
205         DWC_PRINTF("Vd (decimal) = %d\n", vd);
206 #endif
207
208         switch (nd) {
209         case 2:
210                 vd = vd % 100;
211                 DWC_SPRINTF(dd, "%02d", vd);
212                 break;
213         case 3:
214                 vd = vd % 1000;
215                 DWC_SPRINTF(dd, "%03d", vd);
216                 break;
217         case 4:
218                 vd = vd % 10000;
219                 DWC_SPRINTF(dd, "%04d", vd);
220                 break;
221         }
222 #ifdef DEBUG
223         DWC_PRINTF("Display Digits: %s\n", dd);
224 #endif
225
226         message = "connection key";
227         DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
228         dh_dump("HMAC(SHA-256, DHKey, connection key)", sha_result, 32);
229         DWC_MEMCPY(ck, sha_result, 16);
230
231         message = "key derivation key";
232         DWC_HMAC_SHA256(message, DWC_STRLEN(message), dhkey, 32, sha_result);
233         dh_dump("HMAC(SHA-256, DHKey, key derivation key)", sha_result, 32);
234         DWC_MEMCPY(kdk, sha_result, 32);
235
236         return 0;
237 }
238
239
240 #ifdef DH_TEST_VECTORS
241
242 static __u8 dh_a[] = {
243         0x44, 0x00, 0x51, 0xd6,
244         0xf0, 0xb5, 0x5e, 0xa9,
245         0x67, 0xab, 0x31, 0xc6,
246         0x8a, 0x8b, 0x5e, 0x37,
247         0xd9, 0x10, 0xda, 0xe0,
248         0xe2, 0xd4, 0x59, 0xa4,
249         0x86, 0x45, 0x9c, 0xaa,
250         0xdf, 0x36, 0x75, 0x16,
251 };
252
253 static __u8 dh_b[] = {
254         0x5d, 0xae, 0xc7, 0x86,
255         0x79, 0x80, 0xa3, 0x24,
256         0x8c, 0xe3, 0x57, 0x8f,
257         0xc7, 0x5f, 0x1b, 0x0f,
258         0x2d, 0xf8, 0x9d, 0x30,
259         0x6f, 0xa4, 0x52, 0xcd,
260         0xe0, 0x7a, 0x04, 0x8a,
261         0xde, 0xd9, 0x26, 0x56,
262 };
263
264 void dwc_run_dh_test_vectors(void *mem_ctx)
265 {
266         uint8_t pkd[384];
267         uint8_t pkh[384];
268         uint8_t hashd[32];
269         uint8_t hashh[32];
270         uint8_t ck[16];
271         uint8_t kdk[32];
272         char dd[5];
273
274         DWC_PRINTF("\n\n\nDH_TEST_VECTORS\n\n");
275
276         /* compute the PKd and SHA-256(PKd || Nd) */
277         DWC_PRINTF("Computing PKd\n");
278         dwc_dh_pk(mem_ctx, 2, dh_a, pkd, hashd);
279
280         /* compute the PKd and SHA-256(PKh || Nd) */
281         DWC_PRINTF("Computing PKh\n");
282         dwc_dh_pk(mem_ctx, 2, dh_b, pkh, hashh);
283
284         /* compute the dhkey */
285         dwc_dh_derive_keys(mem_ctx, 2, pkh, pkd, dh_a, 0, dd, ck, kdk);
286 }
287 #endif /* DH_TEST_VECTORS */
288
289 #endif /* !CONFIG_MACH_IPMATE */
290
291 #endif /* DWC_CRYPTOLIB */