summaryrefslogtreecommitdiff
path: root/egg/egg-padding.c
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2009-12-13 22:45:37 +0000
committerStef Walter <stef@memberwebs.com>2009-12-14 01:54:00 +0000
commit6c3dbdff0e3efa9e49831fda461168f0b87afa85 (patch)
tree8915eb6e3d921dbd00a93fabcf4acede932b49db /egg/egg-padding.c
parent1cf5f7d8ca78f040f7f5f319e7268733540e7e4d (diff)
downloadgcr-6c3dbdff0e3efa9e49831fda461168f0b87afa85.tar.gz
[egg] Move padding functionality into egg
So other components can use it.
Diffstat (limited to 'egg/egg-padding.c')
-rw-r--r--egg/egg-padding.c302
1 files changed, 302 insertions, 0 deletions
diff --git a/egg/egg-padding.c b/egg/egg-padding.c
new file mode 100644
index 0000000..66699ce
--- /dev/null
+++ b/egg/egg-padding.c
@@ -0,0 +1,302 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "egg-padding.h"
+
+#include <gcrypt.h>
+
+#include "egg/egg-secure-memory.h"
+
+/* ----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+fill_random_nonzero (guchar *data, gsize n_data)
+{
+ guchar *rnd;
+ guint n_zero, i, j;
+
+ gcry_randomize (data, n_data, GCRY_STRONG_RANDOM);
+
+ /* Find any zeros in random data */
+ n_zero = 0;
+ for (i = 0; i < n_data; ++i) {
+ if (data[i] == 0x00)
+ ++n_zero;
+ }
+
+ while (n_zero > 0) {
+ rnd = gcry_random_bytes (n_zero, GCRY_STRONG_RANDOM);
+ n_zero = 0;
+ for (i = 0, j = 0; i < n_data; ++i) {
+ if (data[i] != 0x00)
+ continue;
+
+ /* Use some of the replacement data */
+ data[i] = rnd[j];
+ ++j;
+
+ /* It's zero again :( */
+ if (data[i] == 0x00)
+ n_zero++;
+ }
+
+ gcry_free (rnd);
+ }
+}
+
+static gboolean
+unpad_pkcs1 (guchar bt, EggAllocator alloc, gsize block, const guchar* padded,
+ gsize n_padded, gpointer *raw, gsize *n_raw)
+{
+ const guchar *at;
+
+ if (block && n_padded % block != 0)
+ return FALSE;
+
+ /* Check the header */
+ if (padded[0] != 0x00 || padded[1] != bt)
+ return FALSE;
+
+ /* The first zero byte after the header */
+ at = memchr (padded + 2, 0x00, n_padded - 2);
+ if (!at)
+ return FALSE;
+
+ if (alloc == NULL)
+ alloc = g_realloc;
+
+ ++at;
+ *n_raw = n_padded - (at - padded);
+ if (raw) {
+ *raw = (alloc) (NULL, *n_raw + 1);
+ if (*raw == NULL)
+ return FALSE;
+ memcpy (*raw, at, *n_raw);
+
+ /* Convenience null terminate the result */
+ memset (((guchar*)*raw) + *n_raw, 0, 1);
+ }
+
+ return TRUE;
+}
+
+/* ----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+gboolean
+egg_padding_zero_pad (EggAllocator alloc, gsize block, gconstpointer raw,
+ gsize n_raw, gpointer *padded, gsize *n_padded)
+{
+ guchar *pad;
+ gsize n_pad;
+
+ /*
+ * 0x00 0x00 0x00 ... 0x?? 0x?? 0x?? ...
+ * padding data
+ */
+
+ g_return_val_if_fail (block != 0, FALSE);
+
+ *n_padded = ((n_raw + (block - 1)) / block) * block;
+ g_assert (n_raw <= *n_padded);
+ n_pad = *n_padded - n_raw;
+ g_assert (n_pad < block);
+
+ if (alloc == NULL)
+ alloc = g_realloc;
+
+ if (padded) {
+ *padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
+ if (pad == NULL)
+ return FALSE;
+ memset (pad, 0x00, n_pad);
+ memcpy (pad + n_pad, raw, n_raw);
+ }
+
+ return TRUE;
+}
+
+gboolean
+egg_padding_pkcs1_pad_01 (EggAllocator alloc, gsize block, gconstpointer raw,
+ gsize n_raw, gpointer *padded, gsize *n_padded)
+{
+ guchar *pad;
+ gsize n_pad;
+
+ /*
+ * 0x00 0x01 0xFF 0xFF ... 0x00 0x?? 0x?? 0x?? ...
+ * type padding data
+ */
+
+ g_return_val_if_fail (block != 0, FALSE);
+ g_return_val_if_fail (block > 3, FALSE);
+
+ *n_padded = ((n_raw + 3 + (block - 1)) / block) * block;
+ g_assert (n_raw <= *n_padded);
+ n_pad = *n_padded - n_raw;
+ g_assert (n_pad <= block);
+ g_assert (n_pad >= 3);
+
+ if (alloc == NULL)
+ alloc = g_realloc;
+
+ if (padded) {
+ *padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
+ if (pad == NULL)
+ return FALSE;
+ pad[0] = 0; /* Prefix */
+ pad[1] = 1; /* Block type */
+ memset (pad + 2, 0xFF, n_pad - 3);
+ pad[n_pad - 1] = 0;
+ memcpy (pad + n_pad, raw, n_raw);
+ }
+
+ return TRUE;
+}
+
+gboolean
+egg_padding_pkcs1_pad_02 (EggAllocator alloc, gsize block, gconstpointer raw,
+ gsize n_raw, gpointer *padded, gsize *n_padded)
+{
+ guchar *pad;
+ gsize n_pad;
+
+ /*
+ * 0x00 0x01 0x?? 0x?? ... 0x00 0x?? 0x?? 0x?? ...
+ * type padding data
+ */
+
+ g_return_val_if_fail (block != 0, FALSE);
+ g_return_val_if_fail (block > 3, FALSE);
+
+ *n_padded = ((n_raw + 3 + (block - 1)) / block) * block;
+ g_assert (n_raw <= *n_padded);
+ n_pad = *n_padded - n_raw;
+ g_assert (n_pad <= block);
+ g_assert (n_pad >= 3);
+
+ if (alloc == NULL)
+ alloc = g_realloc;
+
+ if (padded) {
+ *padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
+ if (pad == NULL)
+ return FALSE;
+ pad[0] = 0; /* Prefix */
+ pad[1] = 2; /* Block type */
+ fill_random_nonzero (pad + 2, n_pad - 3);
+ pad[n_pad - 1] = 0;
+ memcpy (pad + n_pad, raw, n_raw);
+ }
+
+ return TRUE;
+}
+
+gboolean
+egg_padding_pkcs1_unpad_01 (EggAllocator alloc, gsize block, gconstpointer padded,
+ gsize n_padded, gpointer *raw, gsize *n_raw)
+{
+ return unpad_pkcs1 (0x01, alloc, block, padded, n_padded, raw, n_raw);
+}
+
+gboolean
+egg_padding_pkcs1_unpad_02 (EggAllocator alloc, gsize block, gconstpointer padded,
+ gsize n_padded, gpointer *raw, gsize *n_raw)
+{
+ return unpad_pkcs1 (0x02, alloc, block, padded, n_padded, raw, n_raw);
+}
+
+gboolean
+egg_padding_pkcs7_pad (EggAllocator alloc, gsize block, gconstpointer raw,
+ gsize n_raw, gpointer *padded, gsize *n_padded)
+{
+ guchar *pad;
+ gsize n_pad;
+
+ g_return_val_if_fail (block != 0, FALSE);
+ g_return_val_if_fail (block < 256, FALSE);
+
+ *n_padded = ((n_raw + block) / block) * block;
+ g_assert (n_raw < *n_padded);
+ n_pad = *n_padded - n_raw;
+ g_assert (n_pad > 0 && n_pad <= block);
+
+ if (alloc == NULL)
+ alloc = g_realloc;
+
+ if (padded) {
+ *padded = pad = (alloc) (NULL, MAX (*n_padded, 1));
+ if (pad == NULL)
+ return FALSE;
+ memcpy (pad, raw, n_raw);
+ memset (pad + n_raw, n_pad, n_pad);
+ }
+
+ return TRUE;
+}
+
+gboolean
+egg_padding_pkcs7_unpad (EggAllocator alloc, gsize block, gconstpointer padded,
+ gsize n_padded, gpointer *raw, gsize *n_raw)
+{
+ const guchar *pad;
+ gsize n_pad, i;
+
+ if (n_padded == 0)
+ return FALSE;
+
+ pad = padded;
+ n_pad = pad[n_padded - 1];
+
+ /* Validate the padding */
+ if (n_pad == 0 || n_pad > 256)
+ return FALSE;
+ if (n_pad > n_padded)
+ return FALSE;
+ if (block && n_pad > block)
+ return FALSE;
+ for (i = n_padded - n_pad; i < n_padded; ++i) {
+ if (pad[i] != n_pad)
+ return FALSE;
+ }
+
+ *n_raw = n_padded - n_pad;
+
+ if (alloc == NULL)
+ alloc = g_realloc;
+
+ if (raw) {
+ *raw = (alloc) (NULL, *n_raw + 1);
+ if (*raw == NULL)
+ return FALSE;
+
+ /* Output the result, null terminated */
+ memcpy (*raw, pad, *n_raw);
+ memset (((guchar*)*raw) + *n_raw, 0, 1);
+ }
+
+ return TRUE;
+}