1 /*
2 * Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
3 *
4 * Author: Shawn Webb
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20
21 #if HAVE_CONF_H
22 #include "clamav-config.h"
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #include <math.h>
34
35 #include <sys/types.h>
36
37 #include <openssl/bio.h>
38 #include <openssl/evp.h>
39
40 // libclamav
41 #include "clamav.h"
42 #include "conv.h"
43
44 /** Get the expected decoded length of a base64-encoded string
45 * @param[in] data Base64-encoded string
46 * @param[in] len length of the string
47 * @return The expected decoded length of the base64-encoded string
48 */
base64_len(const char * data,size_t len)49 static size_t base64_len(const char *data, size_t len)
50 {
51 int padding = 0;
52 size_t i;
53
54 if (!len)
55 return 0;
56
57 for (i = len - 1; i > 0 && data[i] == '='; i--)
58 padding++;
59
60 return (size_t)((3 * len) / 4 - padding);
61 }
62
63 /** Decode a base64-encoded string
64 * @param[in] data The base64-encoded string
65 * @param[in] len Length of the base64-encoded string
66 * @param[out] obuf If obuf is not set to NULL, store the decoded data in obuf. Otherwise, the decoded data is stored in a dynamically-allocated buffer.
67 * @param[out] olen The length of the decoded data
68 * @return The base64-decoded data
69 */
cl_base64_decode(char * data,size_t len,void * obuf,size_t * olen,int oneline)70 void *cl_base64_decode(char *data, size_t len, void *obuf, size_t *olen, int oneline)
71 {
72 BIO *bio, *b64;
73 void *buf;
74
75 buf = (obuf) ? obuf : malloc(base64_len(data, len) + 1);
76 if (!(buf))
77 return NULL;
78
79 b64 = BIO_new(BIO_f_base64());
80 if (!(b64)) {
81 if (!(obuf))
82 free(buf);
83
84 return NULL;
85 }
86
87 bio = BIO_new_mem_buf(data, len);
88 if (!(bio)) {
89 BIO_free(b64);
90 if (!(obuf))
91 free(buf);
92
93 return NULL;
94 }
95
96 bio = BIO_push(b64, bio);
97 if (oneline)
98 BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
99
100 *olen = BIO_read(bio, buf, base64_len(data, len));
101
102 BIO_free_all(bio);
103
104 return buf;
105 }
106
107 /** Base64-encode data
108 * @param[in] data The data to be encoded
109 * @param[in] len The length of the data
110 * @return A pointer to the base64-encoded data. The data is stored in a dynamically-allocated buffer.
111 */
cl_base64_encode(void * data,size_t len)112 char *cl_base64_encode(void *data, size_t len)
113 {
114 BIO *bio, *b64;
115 char *buf, *p;
116 size_t elen;
117
118 b64 = BIO_new(BIO_f_base64());
119 if (!(b64))
120 return NULL;
121 bio = BIO_new(BIO_s_mem());
122 if (!(bio)) {
123 BIO_free(b64);
124 return NULL;
125 }
126
127 bio = BIO_push(b64, bio);
128 BIO_write(bio, data, len);
129
130 BIO_flush(bio);
131 elen = (size_t)BIO_get_mem_data(bio, &buf);
132
133 /* Ensure we're dealing with a NULL-terminated string */
134 p = (char *)malloc(elen + 1);
135 if (NULL == p) {
136 BIO_free(b64);
137 return NULL;
138 }
139 memcpy((void *)p, (void *)buf, elen);
140 p[elen] = 0x00;
141 buf = p;
142
143 BIO_free_all(bio);
144
145 return buf;
146 }
147
148 #if defined(CONV_SELF_TEST)
149
main(int argc,char * argv[])150 int main(int argc, char *argv[])
151 {
152 char *plaintext, *encoded, *decoded;
153 unsigned char *sha_plaintext, *sha_decoded;
154 size_t len;
155 int ret = 0;
156 unsigned int shalen;
157
158 initialize_crypto();
159
160 plaintext = (argv[1]) ? argv[1] : "Hello. This is dog";
161 sha_plaintext = sha256(plaintext, strlen(plaintext), NULL, NULL);
162 if (!(sha_plaintext)) {
163 fprintf(stderr, "Could not generate sha256 of plaintext\n");
164 return 1;
165 }
166
167 encoded = base64_encode(plaintext, strlen(plaintext));
168 if (!(encoded)) {
169 fprintf(stderr, "Could not base64 encode plaintest\n");
170 return 1;
171 }
172 fprintf(stderr, "Base64 encoded: %s\n", encoded);
173
174 decoded = base64_decode(encoded, strlen(encoded), NULL, &len);
175 if (!(decoded)) {
176 fprintf(stderr, "Could not base64 decoded string\n");
177 return 1;
178 }
179
180 sha_decoded = sha256(decoded, len, NULL, &shalen);
181 if (!(sha_decoded)) {
182 fprintf(stderr, "Could not generate sha256 of decoded data\n");
183 return 1;
184 }
185
186 if (memcmp(sha_plaintext, sha_decoded, shalen)) {
187 fprintf(stderr, "Decoded does not match plaintext: %s\n", decoded);
188 ret = 1;
189 }
190
191 free(sha_decoded);
192 free(sha_plaintext);
193 free(encoded);
194 free(decoded);
195
196 cleanup_crypto();
197
198 return ret;
199 }
200
201 #endif
202