/src/dropbear/src/chachapoly.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Dropbear SSH |
3 | | * |
4 | | * Copyright (c) 2002,2003 Matt Johnston |
5 | | * Copyright (c) 2020 by Vladislav Grishenko |
6 | | * All rights reserved. |
7 | | * |
8 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | | * of this software and associated documentation files (the "Software"), to deal |
10 | | * in the Software without restriction, including without limitation the rights |
11 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | | * copies of the Software, and to permit persons to whom the Software is |
13 | | * furnished to do so, subject to the following conditions: |
14 | | * |
15 | | * The above copyright notice and this permission notice shall be included in |
16 | | * all copies or substantial portions of the Software. |
17 | | * |
18 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
24 | | * SOFTWARE. */ |
25 | | |
26 | | #include "includes.h" |
27 | | #include "algo.h" |
28 | | #include "dbutil.h" |
29 | | #include "chachapoly.h" |
30 | | |
31 | | #if DROPBEAR_CHACHA20POLY1305 |
32 | | |
33 | 69.3k | #define CHACHA20_KEY_LEN 32 |
34 | | #define CHACHA20_BLOCKSIZE 8 |
35 | | #define POLY1305_KEY_LEN 32 |
36 | 239k | #define POLY1305_TAG_LEN 16 |
37 | | |
38 | | static const struct ltc_cipher_descriptor dummy = {.name = NULL}; |
39 | | |
40 | | static const struct dropbear_hash dropbear_chachapoly_mac = |
41 | | {NULL, POLY1305_KEY_LEN, POLY1305_TAG_LEN}; |
42 | | |
43 | | const struct dropbear_cipher dropbear_chachapoly = |
44 | | {&dummy, CHACHA20_KEY_LEN*2, CHACHA20_BLOCKSIZE}; |
45 | | |
46 | | static int dropbear_chachapoly_start(int UNUSED(cipher), const unsigned char* UNUSED(IV), |
47 | | const unsigned char *key, int keylen, |
48 | 17.3k | int UNUSED(num_rounds), dropbear_chachapoly_state *state) { |
49 | 17.3k | int err; |
50 | | |
51 | 17.3k | TRACE2(("enter dropbear_chachapoly_start")) |
52 | | |
53 | 17.3k | if (keylen != CHACHA20_KEY_LEN*2) { |
54 | 0 | return CRYPT_ERROR; |
55 | 0 | } |
56 | | |
57 | 17.3k | if ((err = chacha_setup(&state->chacha, key, |
58 | 17.3k | CHACHA20_KEY_LEN, 20)) != CRYPT_OK) { |
59 | 0 | return err; |
60 | 0 | } |
61 | | |
62 | 17.3k | if ((err = chacha_setup(&state->header, key + CHACHA20_KEY_LEN, |
63 | 17.3k | CHACHA20_KEY_LEN, 20) != CRYPT_OK)) { |
64 | 0 | return err; |
65 | 0 | } |
66 | | |
67 | 17.3k | TRACE2(("leave dropbear_chachapoly_start")) |
68 | 17.3k | return CRYPT_OK; |
69 | 17.3k | } |
70 | | |
71 | | static int dropbear_chachapoly_crypt(unsigned int seq, |
72 | | const unsigned char *in, unsigned char *out, |
73 | | unsigned long len, unsigned long taglen, |
74 | 239k | dropbear_chachapoly_state *state, int direction) { |
75 | 239k | poly1305_state poly; |
76 | 239k | unsigned char seqbuf[8], key[POLY1305_KEY_LEN], tag[POLY1305_TAG_LEN]; |
77 | 239k | int err; |
78 | | |
79 | 239k | TRACE2(("enter dropbear_chachapoly_crypt")) |
80 | | |
81 | 239k | if (len < 4 || taglen != POLY1305_TAG_LEN) { |
82 | 0 | return CRYPT_ERROR; |
83 | 0 | } |
84 | | |
85 | 239k | STORE64H((uint64_t)seq, seqbuf); |
86 | 239k | chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 0); |
87 | 239k | if ((err = chacha_keystream(&state->chacha, key, sizeof(key))) != CRYPT_OK) { |
88 | 0 | return err; |
89 | 0 | } |
90 | | |
91 | 239k | poly1305_init(&poly, key, sizeof(key)); |
92 | 239k | if (direction == LTC_DECRYPT) { |
93 | 0 | poly1305_process(&poly, in, len); |
94 | 0 | poly1305_done(&poly, tag, &taglen); |
95 | 0 | if (constant_time_memcmp(in + len, tag, taglen) != 0) { |
96 | 0 | return CRYPT_ERROR; |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | 239k | chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0); |
101 | 239k | if ((err = chacha_crypt(&state->header, in, 4, out)) != CRYPT_OK) { |
102 | 0 | return err; |
103 | 0 | } |
104 | | |
105 | 239k | chacha_ivctr64(&state->chacha, seqbuf, sizeof(seqbuf), 1); |
106 | 239k | if ((err = chacha_crypt(&state->chacha, in + 4, len - 4, out + 4)) != CRYPT_OK) { |
107 | 0 | return err; |
108 | 0 | } |
109 | | |
110 | 239k | if (direction == LTC_ENCRYPT) { |
111 | 239k | poly1305_process(&poly, out, len); |
112 | 239k | poly1305_done(&poly, out + len, &taglen); |
113 | 239k | } |
114 | | |
115 | 239k | TRACE2(("leave dropbear_chachapoly_crypt")) |
116 | 239k | return CRYPT_OK; |
117 | 239k | } |
118 | | |
119 | | static int dropbear_chachapoly_getlength(unsigned int seq, |
120 | | const unsigned char *in, unsigned int *outlen, |
121 | 0 | unsigned long len, dropbear_chachapoly_state *state) { |
122 | 0 | unsigned char seqbuf[8], buf[4]; |
123 | 0 | int err; |
124 | |
|
125 | 0 | TRACE2(("enter dropbear_chachapoly_getlength")) |
126 | |
|
127 | 0 | if (len < sizeof(buf)) { |
128 | 0 | return CRYPT_ERROR; |
129 | 0 | } |
130 | | |
131 | 0 | STORE64H((uint64_t)seq, seqbuf); |
132 | 0 | chacha_ivctr64(&state->header, seqbuf, sizeof(seqbuf), 0); |
133 | 0 | if ((err = chacha_crypt(&state->header, in, sizeof(buf), buf)) != CRYPT_OK) { |
134 | 0 | return err; |
135 | 0 | } |
136 | | |
137 | 0 | LOAD32H(*outlen, buf); |
138 | |
|
139 | 0 | TRACE2(("leave dropbear_chachapoly_getlength")) |
140 | 0 | return CRYPT_OK; |
141 | 0 | } |
142 | | |
143 | | const struct dropbear_cipher_mode dropbear_mode_chachapoly = |
144 | | {(void *)dropbear_chachapoly_start, NULL, NULL, |
145 | | (void *)dropbear_chachapoly_crypt, |
146 | | (void *)dropbear_chachapoly_getlength, &dropbear_chachapoly_mac}; |
147 | | |
148 | | #endif /* DROPBEAR_CHACHA20POLY1305 */ |