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/>.
25 #include <glib/gstdio.h>
27 #include "gcrypt/crypto.h"
29 static void _fail_set(crypto_t c
, gchar
*errmsg
)
35 static crypto_t
_fail(crypto_t c
, gchar
*errmsg
)
41 static gint
_failn(crypto_t c
, gchar
*errmsg
)
47 static crypto_t
_setkey(crypto_t c
, gchar
*key
)
52 g_message("[%s] key=%s", __func__
, key
);
54 c
->cipher
.key
= (gchar
*) crypto_hex2bytes(key
, &keylen
);
55 if (c
->cipher
.key
== NULL
|| keylen
==0)
58 g_strdup("crypto_hex2bytes failed: invalid "
59 "hexadecimal string length")));
62 crypto_dump("c->cipher.key", (guchar
*) c
->cipher
.key
, keylen
);
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
)));
74 if (keylen
> c
->cipher
.keylen
)
76 g_warning("key length exceeds %lu, ignoring the exceeding bytes",keylen
);
77 keylen
= c
->cipher
.keylen
;
81 e
= gcry_cipher_setkey(c
->cipher
.h
, c
->cipher
.key
, keylen
);
85 g_strdup_printf("gcry_cipher_setkey failed: %s",
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
)
99 c
->algo
= gcry_cipher_map_name(algoname
);
102 return (_fail(c
, g_strdup_printf("algorithm `%s' was not available",
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
)
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
);
122 return (_fail(c
, g_strdup_printf("gcry_cipher_open failed: %s",
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
);
133 return (_fail(c
, g_strdup_printf("algorithm `%s' was not available",
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
);
148 _hash_new(c
, algoname
);
152 void crypto_free(crypto_t c
)
157 if (c
->cipher
.h
!= NULL
)
158 gcry_cipher_close(c
->cipher
.h
);
161 g_free(c
->cipher
.key
);
162 c
->cipher
.key
= 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 */)
185 memcpy(out
, data
, dlen
);
187 /* Pad to block length. */
188 if (c
->cipher
.should_pad
== TRUE
&& dlen
< c
->cipher
.blklen
)
192 while (i
< c
->cipher
.blklen
)
197 e
= gcry_cipher_encrypt(c
->cipher
.h
, out
, c
->cipher
.blklen
, NULL
, 0);
201 g_strdup_printf("gcry_cipher_encrypt failed: %s",
206 p
= g_realloc(c
->out
.data
, c
->out
.dlen
+ c
->cipher
.blklen
);
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 */)
223 memcpy(out
, data
, dlen
);
226 e
= gcry_cipher_decrypt(c
->cipher
.h
, out
, c
->cipher
.blklen
, NULL
, 0);
230 g_strdup_printf("gcry_cipher_decrypt failed: %s",
234 n
= c
->cipher
.blklen
;
236 if (c
->cipher
.should_pad
== TRUE
)
238 for (i
=0; i
<n
; ++i
) /* Strip padding. */
241 && (i
>0 || i
==n
|| (i
<n
&& out
[i
+1] == 0x00)) )
249 p
= g_realloc(c
->out
.data
, c
->out
.dlen
+n
); /* Append. */
253 memcpy(&(c
->out
.data
[c
->out
.dlen
]), out
, 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);
264 return (_failn(c
, g_strdup_printf("gcry_cipher_setiv failed: %s",
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
)
279 if (_setiv(c
) != EXIT_SUCCESS
)
280 return (EXIT_FAILURE
);
282 cb
= (c
->mode
== CRYPTO_MODE_ENCRYPT
)
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
);
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
);
309 gint
_hash_exec(crypto_t c
, const guchar
*data
, const gsize size
)
314 dlen
= gcry_md_get_algo_dlen(c
->algo
);
315 n
= dlen
* sizeof(guchar
);
317 c
->out
.data
= g_malloc0(n
);
320 gcry_md_hash_buffer(c
->algo
, c
->out
.data
, data
, size
);
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
);
325 return (EXIT_SUCCESS
);
328 gint
crypto_exec(crypto_t c
, const guchar
*data
, const gsize size
)
330 g_assert(data
!= NULL
);
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
)
347 g_print("%02x", p
[i
++] & 0xff);
348 g_print(" =(%" G_GSIZE_FORMAT
")\n", i
);
351 guchar
*crypto_hex2bytes(const gchar
*hexstr
, gsize
*size
)
361 return (NULL
); /* Invalid hexadecimal string length. */
363 r
= g_malloc0_n(n
/2, sizeof(guchar
));
366 while ( *p
&& (n
= sscanf((gchar
*) p
, "%02x", &b
)) == 1)
374 gchar
*crypto_bytes2hex(const guchar
*data
, const gsize n
)
380 g_assert(data
!= NULL
);
383 crypto_dump("data", data
, n
);
385 s
= g_string_new(NULL
);
389 g_string_append_printf(s
, "%02x", data
[i
++] & 0xff);
392 g_string_free(s
, FALSE
);
397 /* vim: set ts=2 sw=2 tw=72 expandtab: */