2 * Copyright (C) 1993 Branko Lankester
3 * Copyright (C) 1993 Colin Plumb
4 * Copyright (C) 1995 Erik Troan
5 * Copyright (C) 2004 John Ellis
6 * Copyright (C) 2008 - 2016 The Geeqie Team
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * This code implements the MD5 message-digest algorithm.
23 * The algorithm is due to Ron Rivest. This code was
24 * written by Colin Plumb in 1993, no copyright is claimed.
25 * This code is in the public domain; do with it what you wish.
27 * Equivalent code is available from RSA Data Security, Inc.
28 * This code has been tested against that, and is equivalent,
29 * except that you don't need to include two pages of legalese
38 using GQChecksumPtr = std::unique_ptr<GChecksum, decltype(&g_checksum_free)>;
40 constexpr gsize MD5_SIZE = 16;
43 * md5_update_from_file: get the md5 hash of a file
44 * @md5: MD5 checksumming context
46 * @return: TRUE on success
48 * Get the md5 hash of a file.
50 static gboolean md5_update_from_file(GChecksum *md5, const gchar *path)
57 fp = fopen(path, "r");
58 if (!fp) return FALSE;
60 while ((nb_bytes_read = fread(tmp_buf, sizeof (guchar), sizeof(tmp_buf), fp)) > 0)
62 g_checksum_update(md5, tmp_buf, nb_bytes_read);
65 success = (ferror(fp) == 0);
72 * md5_get_string: get the md5 hash of a buffer
73 * @buffer: byte buffer
74 * @buffer_size: buffer size (in bytes)
75 * @return: hash as a hexadecimal string
77 * Get the md5 hash of a buffer. The result is returned
78 * as a hexadecimal string.
80 gchar *md5_get_string(const guchar *buffer, gint buffer_size)
82 GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
83 if (!md5) return nullptr;
85 g_checksum_update(md5.get(), buffer, buffer_size);
87 return g_strdup(g_checksum_get_string(md5.get()));
91 * md5_get_digest_from_file: get the md5 hash of a file
92 * @filename: file name
93 * @digest: 16 bytes buffer receiving the hash code.
94 * @return: TRUE on success
96 * Get the md5 hash of a file. The result is put in
97 * the 16 bytes buffer @digest .
99 gboolean md5_get_digest_from_file(const gchar *path, guchar digest[16])
101 GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
102 if (!md5) return FALSE;
104 if (!md5_update_from_file(md5.get(), path)) return FALSE;
106 gsize digest_size = MD5_SIZE;
107 g_checksum_get_digest(md5.get(), digest, &digest_size);
108 if (digest_size != MD5_SIZE) return FALSE;
114 * md5_get_string_from_file: get the md5 hash of a file
115 * @filename: file name
116 * @return: hash as a hexadecimal string
118 * Get the md5 hash of a file. The result is returned
119 * as a hexadecimal string.
121 gchar *md5_get_string_from_file(const gchar *path)
123 GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
124 if (!md5) return nullptr;
126 if (!md5_update_from_file(md5.get(), path)) return nullptr;
128 return g_strdup(g_checksum_get_string(md5.get()));
131 /* these to and from text string converters were borrowed from
132 * the libgnomeui library, where they are name thumb_digest_to/from_ascii
134 * this version of the from text util does buffer length checking,
135 * and assumes a NULL terminated string.
138 gchar *md5_digest_to_text(const guchar digest[16])
140 static gchar hex_digits[] = "0123456789abcdef";
142 constexpr gsize result_size = 2 * MD5_SIZE;
144 result = static_cast<gchar *>(g_malloc((result_size + 1) * sizeof(gchar)));
145 for (gsize i = 0; i < MD5_SIZE; i++)
147 result[2*i] = hex_digits[digest[i] >> 4];
148 result[2*i+1] = hex_digits[digest[i] & 0xf];
150 result[result_size] = '\0';
155 gboolean md5_digest_from_text(const gchar *text, guchar digest[16])
157 for (gsize i = 0; i < MD5_SIZE; i++)
159 if (text[2*i] == '\0' || text[2*i+1] == '\0') return FALSE;
160 digest[i] = g_ascii_xdigit_value(text[2*i]) << 4 |
161 g_ascii_xdigit_value(text[2*i + 1]);
167 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */