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
39 using GQChecksumPtr = std::unique_ptr<GChecksum, decltype(&g_checksum_free)>;
41 constexpr gsize MD5_SIZE = 16;
44 * md5_update_from_file: get the md5 hash of a file
45 * @md5: MD5 checksumming context
47 * @return: TRUE on success
49 * Get the md5 hash of a file.
51 static gboolean md5_update_from_file(GChecksum *md5, const gchar *path)
58 fp = fopen(path, "r");
59 if (!fp) return FALSE;
61 while ((nb_bytes_read = fread(tmp_buf, sizeof (guchar), sizeof(tmp_buf), fp)) > 0)
63 g_checksum_update(md5, tmp_buf, nb_bytes_read);
66 success = (ferror(fp) == 0);
73 * md5_get_string: get the md5 hash of a buffer
74 * @buffer: byte buffer
75 * @buffer_size: buffer size (in bytes)
76 * @return: hash as a hexadecimal string
78 * Get the md5 hash of a buffer. The result is returned
79 * as a hexadecimal string.
81 gchar *md5_get_string(const guchar *buffer, gint buffer_size)
83 GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
84 if (!md5) return nullptr;
86 g_checksum_update(md5.get(), buffer, buffer_size);
88 return g_strdup(g_checksum_get_string(md5.get()));
92 * md5_get_digest_from_file: get the md5 hash of a file
93 * @filename: file name
94 * @digest: 16 bytes buffer receiving the hash code.
95 * @return: TRUE on success
97 * Get the md5 hash of a file. The result is put in
98 * the 16 bytes buffer @digest .
100 gboolean md5_get_digest_from_file(const gchar *path, guchar digest[16])
102 GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
103 if (!md5) return FALSE;
105 if (!md5_update_from_file(md5.get(), path)) return FALSE;
107 gsize digest_size = MD5_SIZE;
108 g_checksum_get_digest(md5.get(), digest, &digest_size);
109 if (digest_size != MD5_SIZE) return FALSE;
115 * md5_get_string_from_file: get the md5 hash of a file
116 * @filename: file name
117 * @return: hash as a hexadecimal string
119 * Get the md5 hash of a file. The result is returned
120 * as a hexadecimal string.
122 gchar *md5_get_string_from_file(const gchar *path)
124 GQChecksumPtr md5{g_checksum_new(G_CHECKSUM_MD5), g_checksum_free};
125 if (!md5) return nullptr;
127 if (!md5_update_from_file(md5.get(), path)) return nullptr;
129 return g_strdup(g_checksum_get_string(md5.get()));
132 /* these to and from text string converters were borrowed from
133 * the libgnomeui library, where they are name thumb_digest_to/from_ascii
135 * this version of the from text util does buffer length checking,
136 * and assumes a NULL terminated string.
139 gchar *md5_digest_to_text(const guchar digest[16])
141 static gchar hex_digits[] = "0123456789abcdef";
143 constexpr gsize result_size = 2 * MD5_SIZE;
145 result = static_cast<gchar *>(g_malloc((result_size + 1) * sizeof(gchar)));
146 for (gsize i = 0; i < MD5_SIZE; i++)
148 result[2*i] = hex_digits[digest[i] >> 4];
149 result[2*i+1] = hex_digits[digest[i] & 0xf];
151 result[result_size] = '\0';
156 gboolean md5_digest_from_text(const gchar *text, guchar digest[16])
158 for (gsize i = 0; i < MD5_SIZE; i++)
160 if (text[2*i] == '\0' || text[2*i+1] == '\0') return FALSE;
161 digest[i] = g_ascii_xdigit_value(text[2*i]) << 4 |
162 g_ascii_xdigit_value(text[2*i + 1]);
168 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */