Use word "library" in the source file headers
[libquvi.git] / src / gcrypt / crypto.c
blob520b801295a1dda4eefa01cd21881a0189498e93
1 /* libquvi
2 * Copyright (C) 2013 Toni Gundogdu <legatvs@gmail.com>
4 * This file is part of libquvi <http://quvi.sourceforge.net/>.
6 * This library is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Affero General Public
8 * License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General
17 * Public License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
21 #include "config.h"
23 #include <stdlib.h>
24 #include <gcrypt.h>
25 #include <glib/gstdio.h>
27 #include "gcrypt/crypto.h"
29 static void _fail_set(crypto_t c, gchar *errmsg)
31 c->errmsg = errmsg;
32 c->rc = EXIT_FAILURE;
35 static crypto_t _fail(crypto_t c, gchar *errmsg)
37 _fail_set(c, errmsg);
38 return (c);
41 static gint _failn(crypto_t c, gchar *errmsg)
43 _fail_set(c, errmsg);
44 return (c->rc);
47 static crypto_t _setkey(crypto_t c, gchar *key)
49 gcry_error_t e;
50 gsize keylen;
51 #ifdef _1
52 g_message("[%s] key=%s", __func__, key);
53 #endif
54 c->cipher.key = (gchar*) crypto_hex2bytes(key, &keylen);
55 if (c->cipher.key == NULL || keylen ==0)
57 return (_fail(c,
58 g_strdup("crypto_hex2bytes failed: invalid "
59 "hexadecimal string length")));
61 #ifdef _1
62 crypto_dump("c->cipher.key", (guchar*) c->cipher.key, keylen);
63 #endif
64 c->cipher.keylen = gcry_cipher_get_algo_keylen(c->algo);
65 if (c->cipher.keylen ==0)
67 return (_fail(c, g_strdup_printf("gcry_cipher_get_algo_keylen failed "
68 "c->cipher.keylen=%" G_GSIZE_FORMAT", "
69 "keylen=%" G_GSIZE_FORMAT,
70 c->cipher.keylen, keylen)));
73 #ifdef _1
74 if (keylen > c->cipher.keylen)
76 g_warning("key length exceeds %lu, ignoring the exceeding bytes",keylen);
77 keylen = c->cipher.keylen;
79 #endif
81 e = gcry_cipher_setkey(c->cipher.h, c->cipher.key, keylen);
82 if (e != 0)
84 return (_fail(c,
85 g_strdup_printf("gcry_cipher_setkey failed: %s",
86 gpg_strerror(e))));
88 c->rc = EXIT_SUCCESS;
89 return (c);
92 static crypto_t _cipher_new(crypto_t c, gchar *key,
93 const gchar *algoname,
94 const gint cipher_mode,
95 const guint cipher_flags)
97 gcry_error_t e;
99 c->algo = gcry_cipher_map_name(algoname);
100 if (c->algo ==0)
102 return (_fail(c, g_strdup_printf("algorithm `%s' was not available",
103 algoname)));
106 c->cipher.flags = cipher_flags;
107 c->cipher.mode = cipher_mode;
109 c->cipher.should_pad = (cipher_mode != GCRY_CIPHER_MODE_STREAM
110 && cipher_mode != GCRY_CIPHER_MODE_CFB
111 && cipher_mode != GCRY_CIPHER_MODE_OFB)
112 ? TRUE
113 : FALSE;
115 c->cipher.blklen = gcry_cipher_get_algo_blklen(c->algo);
116 if (c->cipher.blklen ==0)
117 return (_fail(c, g_strdup("gcry_cipher_get_algo_blklen failed")));
119 e = gcry_cipher_open(&c->cipher.h, c->algo, cipher_mode, cipher_flags);
120 if (e != 0)
122 return (_fail(c, g_strdup_printf("gcry_cipher_open failed: %s",
123 gpg_strerror(e))));
125 return (_setkey(c, key));
128 static crypto_t _hash_new(crypto_t c, const gchar *algoname)
130 c->algo = gcry_md_map_name(algoname);
131 if (c->algo ==0)
133 return (_fail(c, g_strdup_printf("algorithm `%s' was not available",
134 algoname)));
136 return (c);
139 crypto_t crypto_new(const gchar *algoname, const CryptoMode crypto_mode,
140 gchar *key, const gint cipher_mode,
141 const guint cipher_flags)
143 crypto_t c = g_new0(struct crypto_s, 1);
144 c->mode = crypto_mode;
145 if (crypto_mode != CRYPTO_MODE_HASH)
146 _cipher_new(c, key, algoname, cipher_mode, cipher_flags);
147 else
148 _hash_new(c, algoname);
149 return (c);
152 void crypto_free(crypto_t c)
154 if (c == NULL)
155 return;
157 if (c->cipher.h != NULL)
158 gcry_cipher_close(c->cipher.h);
159 c->cipher.h = NULL;
161 g_free(c->cipher.key);
162 c->cipher.key = NULL;
164 g_free(c->out.data);
165 c->out.data = NULL;
167 g_free(c->errmsg);
168 c->errmsg = NULL;
170 g_free(c);
171 c = NULL;
174 gboolean crypto_ok(crypto_t c)
176 return ((c->rc == EXIT_SUCCESS) ? TRUE:FALSE);
179 static gint _encrypt_blk(crypto_t c, const guchar *data, const gsize dlen,
180 guchar *out /* size: c->blklen */)
182 gcry_error_t e;
183 gpointer p;
185 memcpy(out, data, dlen);
187 /* Pad to block length. */
188 if (c->cipher.should_pad == TRUE && dlen < c->cipher.blklen)
190 gsize i = dlen;
191 out[i++] = 0x80;
192 while (i < c->cipher.blklen)
193 out[i++] = 0x00;
196 /* in-place */
197 e = gcry_cipher_encrypt(c->cipher.h, out, c->cipher.blklen, NULL, 0);
198 if (e != 0)
200 return (_failn(c,
201 g_strdup_printf("gcry_cipher_encrypt failed: %s",
202 gpg_strerror(e))));
205 /* Append. */
206 p = g_realloc(c->out.data, c->out.dlen + c->cipher.blklen);
207 if (p != NULL)
209 c->out.data = p;
210 memcpy(&(c->out.data[c->out.dlen]), out, c->cipher.blklen);
211 c->out.dlen += c->cipher.blklen;
213 return (EXIT_SUCCESS);
216 static gint _decrypt_blk(crypto_t c, const guchar *data, const gsize dlen,
217 guchar *out /* size: c->blk_len */)
219 gcry_error_t e;
220 gpointer p;
221 gsize i, n;
223 memcpy(out, data, dlen);
225 /* in-place */
226 e = gcry_cipher_decrypt(c->cipher.h, out, c->cipher.blklen, NULL, 0);
227 if (e != 0)
229 return (_failn(c,
230 g_strdup_printf("gcry_cipher_decrypt failed: %s",
231 gpg_strerror(e))));
234 n = c->cipher.blklen;
236 if (c->cipher.should_pad == TRUE)
238 for (i=0; i<n; ++i) /* Strip padding. */
240 if (out[i] == 0x80
241 && (i >0 || i ==n || (i<n && out[i+1] == 0x00)) )
243 n = i;
244 break;
249 p = g_realloc(c->out.data, c->out.dlen+n); /* Append. */
250 if (p != NULL)
252 c->out.data = p;
253 memcpy(&(c->out.data[c->out.dlen]), out, n);
254 c->out.dlen += n;
256 return (EXIT_SUCCESS);
259 static gint _setiv(crypto_t c)
261 const gcry_error_t e = gcry_cipher_setiv(c->cipher.h, NULL, 0);
262 if (e != 0)
264 return (_failn(c, g_strdup_printf("gcry_cipher_setiv failed: %s",
265 gpg_strerror(e))));
267 return (EXIT_SUCCESS);
270 typedef gint (*blk_cb)(crypto_t, const guchar*, const gsize, guchar*);
272 static gint _cipher_exec(crypto_t c, const guchar *data, const gsize size)
274 guchar *out;
275 gsize n, m;
276 blk_cb cb;
277 gint r;
279 if (_setiv(c) != EXIT_SUCCESS)
280 return (EXIT_FAILURE);
282 cb = (c->mode == CRYPTO_MODE_ENCRYPT)
283 ? _encrypt_blk
284 : _decrypt_blk;
286 g_assert(c->out.data == NULL);
287 g_assert(c->out.dlen == 0);
289 m = size - (size % c->cipher.blklen);
290 out = g_malloc0(c->cipher.blklen);
291 r = EXIT_SUCCESS;
293 n = 0;
294 while ( (n < m) && (r == EXIT_SUCCESS) )
296 r = cb(c, (guchar*) data+n, c->cipher.blklen, out);
297 n += c->cipher.blklen;
300 if ( (size % c->cipher.blklen) && (r == EXIT_SUCCESS) )
301 r = cb(c, (guchar*) data+n, (size % c->cipher.blklen), out);
303 g_free(out);
304 c->rc = r;
306 return (r);
309 gint _hash_exec(crypto_t c, const guchar *data, const gsize size)
311 guint dlen;
312 gsize n;
314 dlen = gcry_md_get_algo_dlen(c->algo);
315 n = dlen * sizeof(guchar);
317 c->out.data = g_malloc0(n);
318 c->out.dlen = n;
320 gcry_md_hash_buffer(c->algo, c->out.data, data, size);
321 #ifdef _1
322 g_message("[%s] algo=%s", __func__, gcry_md_algo_name(c->algo));
323 g_message("[%s] dlen=%u, c->out.dlen=%lu", __func__, dlen, c->out.dlen);
324 #endif
325 return (EXIT_SUCCESS);
328 gint crypto_exec(crypto_t c, const guchar *data, const gsize size)
330 g_assert(data != NULL);
331 g_assert(size >0);
333 g_assert(c->out.data == NULL);
334 g_assert(c->out.dlen == 0);
336 if (c->mode != CRYPTO_MODE_HASH)
337 return (_cipher_exec(c, data, size));
339 return (_hash_exec(c, data, size));
342 void crypto_dump(const gchar *w, const guchar *p, const gsize n)
344 gsize i = 0;
345 g_print("%s=", w);
346 while (i<n)
347 g_print("%02x", p[i++] & 0xff);
348 g_print(" =(%" G_GSIZE_FORMAT ")\n", i);
351 guchar *crypto_hex2bytes(const gchar *hexstr, gsize *size)
353 const gchar *p;
354 guint n, b;
355 guchar *r;
357 *size = 0;
359 n = strlen(hexstr);
360 if ( (n % 2) ==1)
361 return (NULL); /* Invalid hexadecimal string length. */
363 r = g_malloc0_n(n/2, sizeof(guchar));
364 p = hexstr;
366 while ( *p && (n = sscanf((gchar*) p, "%02x", &b)) == 1)
368 r[(*size)++] = b;
369 p += 2;
371 return (r);
374 gchar *crypto_bytes2hex(const guchar *data, const gsize n)
376 GString *s;
377 gchar *r;
378 gsize i;
380 g_assert(data != NULL);
381 g_assert(n>0);
382 #ifdef _1
383 crypto_dump("data", data, n);
384 #endif
385 s = g_string_new(NULL);
386 i = 0;
388 while (i<n)
389 g_string_append_printf(s, "%02x", data[i++] & 0xff);
391 r = s->str;
392 g_string_free(s, FALSE);
394 return (r);
397 /* vim: set ts=2 sw=2 tw=72 expandtab: */