Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/majn/tgl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--crypto/aes.h2
-rw-r--r--crypto/aes_altern.c132
3 files changed, 130 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac
index 8a70b06..4d2074b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,6 +16,7 @@ LDFLAGS="$LDFLAGS -L/usr/local/lib"
# Checks for libraries.
AC_CHECK_LIB([m], [sqrt])
+AC_CHECK_LIB([gcrypt], [gcry_md_open])
AC_SEARCH_LIBS([clock_gettime], [rt])
EVENT_VER=""
diff --git a/crypto/aes.h b/crypto/aes.h
index 9fe112e..1ebf0b6 100644
--- a/crypto/aes.h
+++ b/crypto/aes.h
@@ -28,7 +28,7 @@
typedef struct TGLC_aes_key {
char _dummy[
#ifdef TGL_AVOID_OPENSSL_AES
-#error Not specified!
+ 32
#else
244
#endif
diff --git a/crypto/aes_altern.c b/crypto/aes_altern.c
index 42ed353..5f99c44 100644
--- a/crypto/aes_altern.c
+++ b/crypto/aes_altern.c
@@ -22,12 +22,136 @@
#ifdef TGL_AVOID_OPENSSL_AES
-// #include <gcrypt/aes.h>
-// Or similar
+/* Marginally speed up compilation */
+#define GCRYPT_NO_MPI_MACROS
+/* Fail-fast when something becomes deprecated. */
+#define GCRYPT_NO_DEPRECATED
+
+#include <assert.h>
+#include <gcrypt.h>
#include "aes.h"
+#include "meta.h"
+#include "rand.h"
+
+#define AES_BLOCK_BITS 128
+#define AES_BLOCK_BYTES (AES_BLOCK_BITS/8)
+#define AES_KEY_BITS 256
+#define AES_KEY_BYTES (AES_KEY_BITS/8)
+
+typedef char check_struct_sizes[(sizeof (TGLC_aes_key) == AES_KEY_BYTES) - 1];
+
+void TGLC_aes_set_encrypt_key (const unsigned char *userKey, const int bits, TGLC_aes_key *key) {
+ assert (bits == AES_KEY_BITS);
+ memcpy (key->_dummy, userKey, AES_KEY_BYTES);
+}
+
+void TGLC_aes_set_decrypt_key (const unsigned char *userKey, const int bits, TGLC_aes_key *key) {
+ TGLC_aes_set_encrypt_key (userKey, bits, key);
+}
+
+// TODO: Try to use gcrypt's internal buf_xor?
+static void do_xor_block (const unsigned char *in, const unsigned char *with, unsigned char *out) {
+ /* TODO: Referencing them as "size_t" (or whatever biggest numerical type available) is probably faster, but also more error-prone. */
+ for (int i = 0; i < 16; ++i) {
+ *out++ = *in++ ^ *with++;
+ }
+}
+
+static gcry_error_t do_ige_encrypt (const unsigned char *in, unsigned char *out,
+ unsigned long n_blocks, gcry_cipher_hd_t cipher, unsigned char *ivec) {
+ /* The docs say, at the end of section 2:
+ * "OpenSSL uses the convention that the first block of the IV is x_0
+ * and the second block is y_0."
+ * Well, no. This is a subtle error: FIRST comes the previous ENcrypted block,
+ * THEN the DEcrypted block.
+ * Also, keep a copy of the old cleartext, in case in == out. */
+ unsigned char buf[2 * 16];
+ unsigned char *prev_x = buf;
+ unsigned char *cur_x = buf + 16;
+ memcpy (prev_x, ivec + 16, 16);
+ const unsigned char *prev_y = ivec;
+
+ /* gcrypt doesn't allow overlapping buffers. Kudos to "reubensammut" for
+ * noticing this. Note that this also works if in == out. */
+ unsigned char tmp[16];
+ for (unsigned long i = 0; i < n_blocks; ++i) {
+ memcpy (cur_x, in, 16);
+ /* Might overwrite 'in'. */
+ do_xor_block (in, prev_y, out);
+ gcry_error_t gcry_error = gcry_cipher_encrypt (cipher, tmp, 16, out, 16);
+ if (gcry_error) {
+ return gcry_error;
+ }
+ do_xor_block (tmp, prev_x, out);
+ prev_y = out; // encrypted is in 'out'
+ in += 16;
+ out += 16;
+ // swap (tmp_x, cur_x);
+ unsigned char *tmp_x = cur_x;
+ cur_x = prev_x;
+ prev_x = tmp_x;
+ }
+ if (n_blocks > 0) {
+ /* OpenSSL updates the IV, so we do that, too.
+ * One could avoid memcpy here, as it's only 16 bytes. */
+ memcpy (ivec + 16, prev_x, 16);
+ memcpy (ivec, prev_y, 16);
+ }
+ return 0;
+}
+
+static gcry_error_t do_ige_decrypt (const unsigned char *in, unsigned char *out,
+ unsigned long n_blocks, gcry_cipher_hd_t cipher, unsigned char *ivec) {
+ /* Also, keep a copy of the old ciphertext, in case in == out. */
+ unsigned char buf[2 * 16];
+ unsigned char *prev_y = buf;
+ unsigned char *cur_y = buf + 16;
+ memcpy (prev_y, ivec, 16);
+ const unsigned char *prev_x = ivec + 16;
+
+ /* gcrypt doesn't allow overlapping buffers. Kudos to "reubensammut" for
+ * noticing this. Note that this also works if in == out. */
+ unsigned char tmp[16];
+ for (unsigned long i = 0; i < n_blocks; ++i) {
+ memcpy (cur_y, in, 16);
+ /* Might overwrite 'in'. */
+ do_xor_block (in, prev_x, out);
+ gcry_error_t gcry_error = gcry_cipher_decrypt (cipher, tmp, 16, out, 16);
+ if (gcry_error) {
+ return gcry_error;
+ }
+ do_xor_block (tmp, prev_y, out);
+ prev_x = out; // decrypted is in 'out'
+ in += 16;
+ out += 16;
+ // swap (tmp_y, cur_y);
+ unsigned char *tmp_y = cur_y;
+ cur_y = prev_y;
+ prev_y = tmp_y;
+ }
+ /* Do not change ivec */
+ return 0;
+}
+
+/* Needs to be given an IV of length 2*AES_BLOCK_BYTES. */
+void TGLC_aes_ige_encrypt (const unsigned char *in, unsigned char *out, size_t length, const TGLC_aes_key *key, unsigned char *ivec, const int enc) {
+ assert (!(length % AES_BLOCK_BYTES));
+
+ /* Set it up. */
+ gcry_cipher_hd_t cipher;
+ gcry_error_t gcry_error = gcry_cipher_open (&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 0);
+ assert (!gcry_error);
+ gcry_cipher_setkey (cipher, key->_dummy, AES_KEY_BYTES);
+
+ if (enc) {
+ gcry_error = do_ige_encrypt(in, out, length / AES_BLOCK_BYTES, cipher, ivec);
+ } else {
+ gcry_error = do_ige_decrypt(in, out, length / AES_BLOCK_BYTES, cipher, ivec);
+ }
+ assert (!gcry_error);
-/* FIXME */
-#error Not yet implemented: OpenSSL-independent defines for aes
+ gcry_cipher_close(cipher);
+}
#endif