[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Adding sha256 and sha512 to C?
From: |
Leo |
Subject: |
Re: Adding sha256 and sha512 to C? |
Date: |
Mon, 20 Jun 2011 00:08:28 +0800 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.3.50 (Mac OS X 10.6.7) |
Sorry for the delay.
On 2011-06-13 06:37 +0800, Paul Eggert wrote:
> That's better, thanks, but I still have two qualms. First, the name
> "sha" is confusing at the Emacs Lisp level: it feels too much like
> "ash". It's not like programmers will be using crypto functions in
> every expression; their names need not be *that* short. How about the
> name "secure-hash" instead? That's pretty short.
Sounds good.
> Second, naming algorithms via bit counts doesn't sound
> forward-looking. SHA-3 is likely to have a 512-bit variant, for
> example. How about using atoms to name the algorithms, e.g., SHA-1,
> SHA-224, SHA-256, etc.? This is more likely to be robust after SHA-3
> comes out, not to mention SHA-4 etc.
>
> + hash_func = &md5_buffer;
>
> There's no need for the "&" here, or in similar assignments to
> hash_func. (And there's no need for multiple spaces before the "=".)
>
> + digest = make_uninit_string (digest_size);
> ...
> + Lisp_Object value = make_uninit_string (2 * digest_size);
>
> There's no need to call make_uninit_string twice, as only one
> string is being returned. Any temporary buffer for the digest can
> be put into the C stack. Or, perhaps better, use the same
> uninitialized string for both the binary digest and the text
> digest, and run the binary-to-text loop backwards (and without
> using sprintf) so that the loop doesn't stomp on its own work.
> Something like this:
>
> unsigned char *p = SDATA (digest);
> for (i = digest_size - 1; i >= 0; i--)
> {
> static char const hexdigit[16] = "0123456789abcdef";
> int p_i = p[i];
> p[2 * i] = hexdigit[p_i >> 4];
> p[2 * i + 1] = hexdigit[p_i & 0xf];
> }
Thanks for the suggestion.
> The text-vs-binary checksum thing seems to be enough of a hassle that
> perhaps it should be pulled out into a separate function, rather than
> as a flag to the sha/secure-hash function. That is, secure-hash could
> always return the text form, and if someone wants a binary form they
> could call the text-to-binary converter.
>
> Won't there need to be changes to the Emacs Lisp reference manual, and
> to NEWS?
Will take care of the NEWS entry when committing.
Leo
=== modified file 'lisp/subr.el'
--- lisp/subr.el 2011-06-15 17:30:41 +0000
+++ lisp/subr.el 2011-06-19 16:06:58 +0000
@@ -2600,6 +2600,14 @@
(get-char-property (1- (field-end pos)) 'field)
raw-field)))
+(defun sha1 (object &optional start end binary)
+ "Return the SHA1 (Secure Hash Algorithm) of an OBJECT.
+OBJECT is either a string or a buffer. Optional arguments START and
+END are character positions specifying which portion of OBJECT for
+computing the hash. If BINARY is non-nil, return a string in binary
+form."
+ (secure-hash 'sha1 object start end binary))
+
;;;; Support for yanking and text properties.
=== modified file 'src/deps.mk'
--- src/deps.mk 2011-05-24 08:22:58 +0000
+++ src/deps.mk 2011-06-19 15:46:13 +0000
@@ -284,8 +284,8 @@
floatfns.o: floatfns.c syssignal.h lisp.h globals.h $(config_h)
fns.o: fns.c commands.h lisp.h $(config_h) frame.h buffer.h character.h \
keyboard.h keymap.h window.h $(INTERVALS_H) coding.h ../lib/md5.h \
- ../lib/sha1.h blockinput.h atimer.h systime.h xterm.h ../lib/unistd.h \
- globals.h
+ ../lib/sha1.h ../lib/sha256.h ../lib/sha512.h blockinput.h atimer.h \
+ systime.h xterm.h ../lib/unistd.h globals.h
print.o: print.c process.h frame.h window.h buffer.h keyboard.h character.h \
lisp.h globals.h $(config_h) termchar.h $(INTERVALS_H) msdos.h termhooks.h \
blockinput.h atimer.h systime.h font.h charset.h coding.h ccl.h \
=== modified file 'src/fns.c'
--- src/fns.c 2011-06-17 15:18:54 +0000
+++ src/fns.c 2011-06-19 15:46:13 +0000
@@ -51,6 +51,8 @@
static Lisp_Object Qwidget_type;
static Lisp_Object Qcodeset, Qdays, Qmonths, Qpaper;
+static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512;
+
static int internal_equal (Lisp_Object , Lisp_Object, int, int);
#ifndef HAVE_UNISTD_H
@@ -4550,21 +4552,18 @@
/************************************************************************
- MD5 and SHA1
+ MD5, SHA-1, and SHA-2
************************************************************************/
#include "md5.h"
#include "sha1.h"
-
-/* Convert a possibly-signed character to an unsigned character. This is
- a bit safer than casting to unsigned char, since it catches some type
- errors that the cast doesn't. */
-static inline unsigned char to_uchar (char ch) { return ch; }
-
-/* TYPE: 0 for md5, 1 for sha1. */
+#include "sha256.h"
+#include "sha512.h"
+
+/* ALGORITHM is a symbol: md5, sha1, sha224 and so on. */
static Lisp_Object
-crypto_hash_function (int type, Lisp_Object object, Lisp_Object start,
Lisp_Object end, Lisp_Object coding_system, Lisp_Object noerror, Lisp_Object
binary)
+secure_hash (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start,
Lisp_Object end, Lisp_Object coding_system, Lisp_Object noerror, Lisp_Object
binary)
{
int i;
EMACS_INT size;
@@ -4574,7 +4573,11 @@
register EMACS_INT b, e;
register struct buffer *bp;
EMACS_INT temp;
- Lisp_Object res=Qnil;
+ int digest_size;
+ void *(*hash_func) (const char *, size_t, void *);
+ Lisp_Object digest;
+
+ CHECK_SYMBOL (algorithm);
if (STRINGP (object))
{
@@ -4745,47 +4748,61 @@
object = code_convert_string (object, coding_system, Qnil, 1, 0, 0);
}
- switch (type)
- {
- case 0: /* MD5 */
- {
- char digest[16];
- md5_buffer (SSDATA (object) + start_byte,
- SBYTES (object) - (size_byte - end_byte),
- digest);
-
- if (NILP (binary))
- {
- char value[33];
- for (i = 0; i < 16; i++)
- sprintf (&value[2 * i], "%02x", to_uchar (digest[i]));
- res = make_string (value, 32);
- }
- else
- res = make_string (digest, 16);
- break;
- }
-
- case 1: /* SHA1 */
- {
- char digest[20];
- sha1_buffer (SSDATA (object) + start_byte,
- SBYTES (object) - (size_byte - end_byte),
- digest);
- if (NILP (binary))
- {
- char value[41];
- for (i = 0; i < 20; i++)
- sprintf (&value[2 * i], "%02x", to_uchar (digest[i]));
- res = make_string (value, 40);
- }
- else
- res = make_string (digest, 20);
- break;
- }
- }
-
- return res;
+ if (EQ (algorithm, Qmd5))
+ {
+ digest_size = MD5_DIGEST_SIZE;
+ hash_func = md5_buffer;
+ }
+ else if (EQ (algorithm, Qsha1))
+ {
+ digest_size = SHA1_DIGEST_SIZE;
+ hash_func = sha1_buffer;
+ }
+ else if (EQ (algorithm, Qsha224))
+ {
+ digest_size = SHA224_DIGEST_SIZE;
+ hash_func = sha224_buffer;
+ }
+ else if (EQ (algorithm, Qsha256))
+ {
+ digest_size = SHA256_DIGEST_SIZE;
+ hash_func = sha256_buffer;
+ }
+ else if (EQ (algorithm, Qsha384))
+ {
+ digest_size = SHA384_DIGEST_SIZE;
+ hash_func = sha384_buffer;
+ }
+ else if (EQ (algorithm, Qsha512))
+ {
+ digest_size = SHA512_DIGEST_SIZE;
+ hash_func = sha512_buffer;
+ }
+ else
+ error ("Invalid algorithm arg: %s", SDATA (Fsymbol_name (algorithm)));
+
+ /* allocate 2 times the size of digest_size so that it can be
+ re-used to hold the hexified value */
+ digest = make_uninit_string (digest_size * 2);
+
+ hash_func (SSDATA (object) + start_byte,
+ SBYTES (object) - (size_byte - end_byte),
+ SSDATA (digest));
+
+ if (NILP (binary))
+ {
+ unsigned char *p = SDATA (digest);
+ for (i = digest_size - 1; i >= 0; i--)
+ {
+ static char const hexdigit[16] = "0123456789abcdef";
+ int p_i = p[i];
+ p[2 * i] = hexdigit[p_i >> 4];
+ p[2 * i + 1] = hexdigit[p_i & 0xf];
+ }
+ return digest;
+ }
+ else
+ return make_unibyte_string (SDATA (digest), digest_size);
}
DEFUN ("md5", Fmd5, Smd5, 1, 5, 0,
@@ -4817,25 +4834,31 @@
guesswork fails. Normally, an error is signaled in such case. */)
(Lisp_Object object, Lisp_Object start, Lisp_Object end, Lisp_Object
coding_system, Lisp_Object noerror)
{
- return crypto_hash_function (0, object, start, end, coding_system, noerror,
Qnil);
+ return secure_hash (Qmd5, object, start, end, coding_system, noerror, Qnil);
}
-DEFUN ("sha1", Fsha1, Ssha1, 1, 4, 0,
- doc: /* Return the SHA-1 (Secure Hash Algorithm) of an OBJECT.
-
-OBJECT is either a string or a buffer. Optional arguments START and
-END are character positions specifying which portion of OBJECT for
-computing the hash. If BINARY is non-nil, return a string in binary
-form. */)
- (Lisp_Object object, Lisp_Object start, Lisp_Object end, Lisp_Object
binary)
+DEFUN ("secure-hash", Fsecure_hash, Ssecure_hash, 2, 5, 0,
+ doc: /* Return the secure hash of an OBJECT.
+ALGORITHM is a symbol: md5, sha1, sha224, sha256, sha384 or sha512.
+OBJECT is either a string or a buffer.
+Optional arguments START and END are character positions specifying
+which portion of OBJECT for computing the hash. If BINARY is non-nil,
+return a string in binary form. */)
+ (Lisp_Object algorithm, Lisp_Object object, Lisp_Object start, Lisp_Object
end, Lisp_Object binary)
{
- return crypto_hash_function (1, object, start, end, Qnil, Qnil, binary);
+ return secure_hash (algorithm, object, start, end, Qnil, Qnil, binary);
}
-
void
syms_of_fns (void)
{
+ DEFSYM (Qmd5, "md5");
+ DEFSYM (Qsha1, "sha1");
+ DEFSYM (Qsha224, "sha224");
+ DEFSYM (Qsha256, "sha256");
+ DEFSYM (Qsha384, "sha384");
+ DEFSYM (Qsha512, "sha512");
+
/* Hash table stuff. */
Qhash_table_p = intern_c_string ("hash-table-p");
staticpro (&Qhash_table_p);
@@ -5004,7 +5027,7 @@
defsubr (&Sbase64_encode_string);
defsubr (&Sbase64_decode_string);
defsubr (&Smd5);
- defsubr (&Ssha1);
+ defsubr (&Ssecure_hash);
defsubr (&Slocale_info);
}
=== modified file 'src/makefile.w32-in'
--- src/makefile.w32-in 2011-06-12 02:48:18 +0000
+++ src/makefile.w32-in 2011-06-19 15:46:13 +0000
@@ -867,6 +867,8 @@
$(EMACS_ROOT)/nt/inc/sys/time.h \
$(EMACS_ROOT)/lib/md5.h \
$(EMACS_ROOT)/lib/sha1.h \
+ $(EMACS_ROOT)/lib/sha256.h \
+ $(EMACS_ROOT)/lib/sha512.h \
$(LISP_H) \
$(SRC)/atimer.h \
$(SRC)/blockinput.h \
- Re: Adding sha256 and sha512 to C?, (continued)
- Re: Adding sha256 and sha512 to C?, Leo, 2011/06/11
- Re: Adding sha256 and sha512 to C?, Eli Zaretskii, 2011/06/11
- Re: Adding sha256 and sha512 to C?, Paul Eggert, 2011/06/11
- Re: Adding sha256 and sha512 to C?, Juanma Barranquero, 2011/06/11
- Re: Adding sha256 and sha512 to C?, YAMAMOTO Mitsuharu, 2011/06/11
- Re: Adding sha256 and sha512 to C?, Leo, 2011/06/12
- Re: Adding sha256 and sha512 to C?, Thien-Thi Nguyen, 2011/06/12
- Re: Adding sha256 and sha512 to C?, Deniz Dogan, 2011/06/12
- Re: Adding sha256 and sha512 to C?, Richard Riley, 2011/06/12
- Re: Adding sha256 and sha512 to C?, Paul Eggert, 2011/06/12
- Re: Adding sha256 and sha512 to C?,
Leo <=