summaryrefslogtreecommitdiff
path: root/glib/glib/gchecksum.c
diff options
context:
space:
mode:
authorDan Nicholson <dbn.lists@gmail.com>2014-02-03 15:41:27 -0800
committerDan Nicholson <dbn.lists@gmail.com>2014-02-03 15:41:27 -0800
commit90320817dc06052de780b406ad74db22845835ba (patch)
treeae82c1f24b63dac48c60110819da8e0707202d30 /glib/glib/gchecksum.c
parente1d44d2362061a4cbd002ce059f1ac9dd78d971a (diff)
downloadpkg-config-90320817dc06052de780b406ad74db22845835ba.tar.gz
glib: Update snapshot version to 2.38.2
This is the latest stable release from upstream. Patches have been refreshed, including putting the removal of most pkg-config checks into the glib-only patch. A few more files, most notably the large NEWS file, have also been removed from the repo to keep the size of the snapshot down.
Diffstat (limited to 'glib/glib/gchecksum.c')
-rw-r--r--glib/glib/gchecksum.c357
1 files changed, 351 insertions, 6 deletions
diff --git a/glib/glib/gchecksum.c b/glib/glib/gchecksum.c
index f543d96..4dc8558 100644
--- a/glib/glib/gchecksum.c
+++ b/glib/glib/gchecksum.c
@@ -54,7 +54,7 @@
* Support for checksums has been added in GLib 2.16
**/
-#define IS_VALID_TYPE(type) ((type) >= G_CHECKSUM_MD5 && (type) <= G_CHECKSUM_SHA256)
+#define IS_VALID_TYPE(type) ((type) >= G_CHECKSUM_MD5 && (type) <= G_CHECKSUM_SHA512)
/* The fact that these are lower case characters is part of the ABI */
static const gchar hex_digits[] = "0123456789abcdef";
@@ -102,6 +102,21 @@ typedef struct
guchar digest[SHA256_DIGEST_LEN];
} Sha256sum;
+#define SHA512_BLOCK_LEN 128 /* 1024 bits message block */
+#define SHA512_DIGEST_LEN 64
+
+typedef struct
+{
+ guint64 H[8];
+
+ guint8 block[SHA512_BLOCK_LEN];
+ guint8 block_len;
+
+ guint64 data_len[2];
+
+ guchar digest[SHA512_DIGEST_LEN];
+} Sha512sum;
+
struct _GChecksum
{
GChecksumType type;
@@ -112,6 +127,7 @@ struct _GChecksum
Md5sum md5;
Sha1sum sha1;
Sha256sum sha256;
+ Sha512sum sha512;
} sum;
};
@@ -1069,6 +1085,284 @@ sha256_sum_digest (Sha256sum *sha256,
digest[i] = sha256->digest[i];
}
+/*
+ * SHA-512 Checksum
+ *
+ * Implemented following FIPS-180-2 standard at
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf.
+ * References in the form [§x.y.z] map to sections in that document.
+ *
+ * Author: Eduardo Lima Mitev <elima@igalia.com>
+ */
+
+/* SHA-384 and SHA-512 functions [§4.1.3] */
+#define Ch(x,y,z) ((x & y) ^ (~x & z))
+#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z))
+#define SHR(n,x) (x >> n)
+#define ROTR(n,x) (SHR (n, x) | (x << (64 - n)))
+#define SIGMA0(x) (ROTR (28, x) ^ ROTR (34, x) ^ ROTR (39, x))
+#define SIGMA1(x) (ROTR (14, x) ^ ROTR (18, x) ^ ROTR (41, x))
+#define sigma0(x) (ROTR ( 1, x) ^ ROTR ( 8, x) ^ SHR ( 7, x))
+#define sigma1(x) (ROTR (19, x) ^ ROTR (61, x) ^ SHR ( 6, x))
+
+#define PUT_UINT64(n,b,i) G_STMT_START{ \
+ (b)[(i) ] = (guint8) (n >> 56); \
+ (b)[(i) + 1] = (guint8) (n >> 48); \
+ (b)[(i) + 2] = (guint8) (n >> 40); \
+ (b)[(i) + 3] = (guint8) (n >> 32); \
+ (b)[(i) + 4] = (guint8) (n >> 24); \
+ (b)[(i) + 5] = (guint8) (n >> 16); \
+ (b)[(i) + 6] = (guint8) (n >> 8); \
+ (b)[(i) + 7] = (guint8) (n ); } G_STMT_END
+
+static void
+sha512_sum_init (Sha512sum *sha512)
+{
+ /* Initial Hash Value [§5.3.4] */
+ sha512->H[0] = 0x6a09e667f3bcc908;
+ sha512->H[1] = 0xbb67ae8584caa73b;
+ sha512->H[2] = 0x3c6ef372fe94f82b;
+ sha512->H[3] = 0xa54ff53a5f1d36f1;
+ sha512->H[4] = 0x510e527fade682d1;
+ sha512->H[5] = 0x9b05688c2b3e6c1f;
+ sha512->H[6] = 0x1f83d9abfb41bd6b;
+ sha512->H[7] = 0x5be0cd19137e2179;
+
+ sha512->block_len = 0;
+
+ sha512->data_len[0] = 0;
+ sha512->data_len[1] = 0;
+}
+
+/* SHA-384 and SHA-512 constants [§4.2.3] */
+static const guint64 SHA512_K[80] = {
+ 0x428a2f98d728ae22, 0x7137449123ef65cd,
+ 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
+ 0x3956c25bf348b538, 0x59f111f1b605d019,
+ 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
+ 0xd807aa98a3030242, 0x12835b0145706fbe,
+ 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+ 0x72be5d74f27b896f, 0x80deb1fe3b1696b1,
+ 0x9bdc06a725c71235, 0xc19bf174cf692694,
+ 0xe49b69c19ef14ad2, 0xefbe4786384f25e3,
+ 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
+ 0x2de92c6f592b0275, 0x4a7484aa6ea6e483,
+ 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+ 0x983e5152ee66dfab, 0xa831c66d2db43210,
+ 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
+ 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
+ 0x06ca6351e003826f, 0x142929670a0e6e70,
+ 0x27b70a8546d22ffc, 0x2e1b21385c26c926,
+ 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+ 0x650a73548baf63de, 0x766a0abb3c77b2a8,
+ 0x81c2c92e47edaee6, 0x92722c851482353b,
+ 0xa2bfe8a14cf10364, 0xa81a664bbc423001,
+ 0xc24b8b70d0f89791, 0xc76c51a30654be30,
+ 0xd192e819d6ef5218, 0xd69906245565a910,
+ 0xf40e35855771202a, 0x106aa07032bbd1b8,
+ 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
+ 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
+ 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb,
+ 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
+ 0x748f82ee5defb2fc, 0x78a5636f43172f60,
+ 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+ 0x90befffa23631e28, 0xa4506cebde82bde9,
+ 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
+ 0xca273eceea26619c, 0xd186b8c721c0c207,
+ 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
+ 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
+ 0x113f9804bef90dae, 0x1b710b35131c471b,
+ 0x28db77f523047d84, 0x32caab7b40c72493,
+ 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
+ 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a,
+ 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
+};
+
+static void
+sha512_transform (guint64 H[8],
+ guint8 const data[SHA512_BLOCK_LEN])
+{
+ gint i;
+ gint t;
+ guint64 a, b, c, d, e, f, g, h;
+ guint64 M[16];
+ guint64 W[80];
+
+ /* SHA-512 hash computation [§6.3.2] */
+
+ /* prepare the message schedule */
+ for (i = 0; i < 16; i++)
+ {
+ gint p = i * 8;
+
+ M[i] =
+ ((guint64) data[p + 0] << 56) |
+ ((guint64) data[p + 1] << 48) |
+ ((guint64) data[p + 2] << 40) |
+ ((guint64) data[p + 3] << 32) |
+ ((guint64) data[p + 4] << 24) |
+ ((guint64) data[p + 5] << 16) |
+ ((guint64) data[p + 6] << 8) |
+ ((guint64) data[p + 7] );
+ }
+
+ for (t = 0; t < 80; t++)
+ if (t < 16)
+ W[t] = M[t];
+ else
+ W[t] = sigma1 (W[t - 2]) + W[t - 7] + sigma0 (W[t - 15]) + W[t - 16];
+
+ /* initialize the eight working variables */
+ a = H[0];
+ b = H[1];
+ c = H[2];
+ d = H[3];
+ e = H[4];
+ f = H[5];
+ g = H[6];
+ h = H[7];
+
+ for (t = 0; t < 80; t++)
+ {
+ guint64 T1, T2;
+
+ T1 = h + SIGMA1 (e) + Ch (e, f, g) + SHA512_K[t] + W[t];
+ T2 = SIGMA0 (a) + Maj (a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+
+ /* Compute the intermediate hash value H */
+ H[0] += a;
+ H[1] += b;
+ H[2] += c;
+ H[3] += d;
+ H[4] += e;
+ H[5] += f;
+ H[6] += g;
+ H[7] += h;
+}
+
+static void
+sha512_sum_update (Sha512sum *sha512,
+ const guchar *buffer,
+ gsize length)
+{
+ gsize block_left, offset = 0;
+
+ if (length == 0)
+ return;
+
+ sha512->data_len[0] += length * 8;
+ if (sha512->data_len[0] < length)
+ sha512->data_len[1]++;
+
+ /* try to fill current block */
+ block_left = SHA512_BLOCK_LEN - sha512->block_len;
+ if (block_left > 0)
+ {
+ gsize fill_len;
+
+ fill_len = MIN (block_left, length);
+ memcpy (sha512->block + sha512->block_len, buffer, fill_len);
+ sha512->block_len += fill_len;
+ length -= fill_len;
+ offset += fill_len;
+
+ if (sha512->block_len == SHA512_BLOCK_LEN)
+ {
+ sha512_transform (sha512->H, sha512->block);
+ sha512->block_len = 0;
+ }
+ }
+
+ /* process complete blocks */
+ while (length >= SHA512_BLOCK_LEN)
+ {
+ memcpy (sha512->block, buffer + offset, SHA512_BLOCK_LEN);
+
+ sha512_transform (sha512->H, sha512->block);
+
+ length -= SHA512_BLOCK_LEN;
+ offset += SHA512_BLOCK_LEN;
+ }
+
+ /* keep remaining data for next block */
+ if (length > 0)
+ {
+ memcpy (sha512->block, buffer + offset, length);
+ sha512->block_len = length;
+ }
+}
+
+static void
+sha512_sum_close (Sha512sum *sha512)
+{
+ guint l;
+ gint zeros;
+ guint8 pad[SHA512_BLOCK_LEN * 2] = { 0, };
+ guint pad_len = 0;
+ gint i;
+
+ /* apply padding [§5.1.2] */
+ l = sha512->block_len * 8;
+ zeros = 896 - (l + 1);
+
+ if (zeros < 0)
+ zeros += 128 * 8;
+
+ pad[0] = 0x80; /* 1000 0000 */
+ zeros -= 7;
+ pad_len++;
+
+ memset (pad + pad_len, 0x00, zeros / 8);
+ pad_len += zeros / 8;
+ zeros = zeros % 8;
+
+ /* put message bit length at the end of padding */
+ PUT_UINT64 (sha512->data_len[1], pad, pad_len);
+ pad_len += 8;
+
+ PUT_UINT64 (sha512->data_len[0], pad, pad_len);
+ pad_len += 8;
+
+ /* update checksum with the padded block */
+ sha512_sum_update (sha512, pad, pad_len);
+
+ /* copy resulting 64-bit words into digest */
+ for (i = 0; i < 8; i++)
+ PUT_UINT64 (sha512->H[i], sha512->digest, i * 8);
+}
+
+static gchar *
+sha512_sum_to_string (Sha512sum *sha512)
+{
+ return digest_to_string (sha512->digest, SHA512_DIGEST_LEN);
+}
+
+static void
+sha512_sum_digest (Sha512sum *sha512,
+ guint8 *digest)
+{
+ memcpy (digest, sha512->digest, SHA512_DIGEST_LEN);
+}
+
+#undef Ch
+#undef Maj
+#undef SHR
+#undef ROTR
+#undef SIGMA0
+#undef SIGMA1
+#undef sigma0
+#undef sigma1
+
+#undef PUT_UINT64
/*
* Public API
@@ -1101,6 +1395,9 @@ g_checksum_type_get_length (GChecksumType checksum_type)
case G_CHECKSUM_SHA256:
len = SHA256_DIGEST_LEN;
break;
+ case G_CHECKSUM_SHA512:
+ len = SHA512_DIGEST_LEN;
+ break;
default:
len = -1;
break;
@@ -1127,7 +1424,7 @@ g_checksum_type_get_length (GChecksumType checksum_type)
* will be closed and it won't be possible to call g_checksum_update()
* on it anymore.
*
- * Return value: the newly created #GChecksum, or %NULL.
+ * Return value: (transfer full): the newly created #GChecksum, or %NULL.
* Use g_checksum_free() to free the memory allocated by it.
*
* Since: 2.16
@@ -1175,6 +1472,9 @@ g_checksum_reset (GChecksum *checksum)
case G_CHECKSUM_SHA256:
sha256_sum_init (&(checksum->sum.sha256));
break;
+ case G_CHECKSUM_SHA512:
+ sha512_sum_init (&(checksum->sum.sha512));
+ break;
default:
g_assert_not_reached ();
break;
@@ -1231,7 +1531,7 @@ g_checksum_free (GChecksum *checksum)
/**
* g_checksum_update:
* @checksum: a #GChecksum
- * @data: buffer used to compute the checksum
+ * @data: (array length=length) (element-type guint8): buffer used to compute the checksum
* @length: size of the buffer, or -1 if it is a null-terminated string.
*
* Feeds @data into an existing #GChecksum. The checksum must still be
@@ -1253,7 +1553,7 @@ g_checksum_update (GChecksum *checksum,
if (checksum->digest_str)
{
- g_warning ("The checksum `%s' has been closed and cannot be updated "
+ g_warning ("The checksum '%s' has been closed and cannot be updated "
"anymore.",
checksum->digest_str);
return;
@@ -1270,6 +1570,9 @@ g_checksum_update (GChecksum *checksum,
case G_CHECKSUM_SHA256:
sha256_sum_update (&(checksum->sum.sha256), data, length);
break;
+ case G_CHECKSUM_SHA512:
+ sha512_sum_update (&(checksum->sum.sha512), data, length);
+ break;
default:
g_assert_not_reached ();
break;
@@ -1317,6 +1620,10 @@ g_checksum_get_string (GChecksum *checksum)
sha256_sum_close (&(checksum->sum.sha256));
str = sha256_sum_to_string (&(checksum->sum.sha256));
break;
+ case G_CHECKSUM_SHA512:
+ sha512_sum_close (&(checksum->sum.sha512));
+ str = sha512_sum_to_string (&(checksum->sum.sha512));
+ break;
default:
g_assert_not_reached ();
break;
@@ -1328,7 +1635,7 @@ g_checksum_get_string (GChecksum *checksum)
}
/**
- * g_checksum_get_digest:
+ * g_checksum_get_digest: (skip)
* @checksum: a #GChecksum
* @buffer: output buffer
* @digest_len: an inout parameter. The caller initializes it to the size of @buffer.
@@ -1384,6 +1691,14 @@ g_checksum_get_digest (GChecksum *checksum,
}
sha256_sum_digest (&(checksum->sum.sha256), buffer);
break;
+ case G_CHECKSUM_SHA512:
+ if (checksum_open)
+ {
+ sha512_sum_close (&(checksum->sum.sha512));
+ str = sha512_sum_to_string (&(checksum->sum.sha512));
+ }
+ sha512_sum_digest (&(checksum->sum.sha512), buffer);
+ break;
default:
g_assert_not_reached ();
break;
@@ -1398,7 +1713,7 @@ g_checksum_get_digest (GChecksum *checksum,
/**
* g_compute_checksum_for_data:
* @checksum_type: a #GChecksumType
- * @data: binary blob to compute the digest of
+ * @data: (array length=length) (element-type guint8): binary blob to compute the digest of
* @length: length of @data
*
* Computes the checksum for a binary @data of @length. This is a
@@ -1462,3 +1777,33 @@ g_compute_checksum_for_string (GChecksumType checksum_type,
return g_compute_checksum_for_data (checksum_type, (const guchar *) str, length);
}
+
+/**
+ * g_compute_checksum_for_bytes:
+ * @checksum_type: a #GChecksumType
+ * @data: binary blob to compute the digest of
+ *
+ * Computes the checksum for a binary @data. This is a
+ * convenience wrapper for g_checksum_new(), g_checksum_get_string()
+ * and g_checksum_free().
+ *
+ * The hexadecimal string returned will be in lower case.
+ *
+ * Return value: the digest of the binary data as a string in hexadecimal.
+ * The returned string should be freed with g_free() when done using it.
+ *
+ * Since: 2.34
+ */
+gchar *
+g_compute_checksum_for_bytes (GChecksumType checksum_type,
+ GBytes *data)
+{
+ gconstpointer byte_data;
+ gsize length;
+
+ g_return_val_if_fail (IS_VALID_TYPE (checksum_type), NULL);
+ g_return_val_if_fail (data != NULL, NULL);
+
+ byte_data = g_bytes_get_data (data, &length);
+ return g_compute_checksum_for_data (checksum_type, byte_data, length);
+}