summaryrefslogtreecommitdiff
path: root/mysys/sha1.c
diff options
context:
space:
mode:
Diffstat (limited to 'mysys/sha1.c')
-rw-r--r--mysys/sha1.c392
1 files changed, 392 insertions, 0 deletions
diff --git a/mysys/sha1.c b/mysys/sha1.c
new file mode 100644
index 00000000000..5271b369b6c
--- /dev/null
+++ b/mysys/sha1.c
@@ -0,0 +1,392 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ Original Source from: http://www.faqs.org/rfcs/rfc3174.html
+
+ DESCRIPTION
+ This file implements the Secure Hashing Algorithm 1 as
+ defined in FIPS PUB 180-1 published April 17, 1995.
+
+ The SHA-1, produces a 160-bit message digest for a given data
+ stream. It should take about 2**n steps to find a message with the
+ same digest as a given message and 2**(n/2) to find any two
+ messages with the same digest, when n is the digest size in bits.
+ Therefore, this algorithm can serve as a means of providing a
+ "fingerprint" for a message.
+
+ PORTABILITY ISSUES
+ SHA-1 is defined in terms of 32-bit "words". This code uses
+ <stdint.h> (included via "sha1.h" to define 32 and 8 bit unsigned
+ integer types. If your C compiler does not support 32 bit unsigned
+ integers, this code is not appropriate.
+
+ CAVEATS
+ SHA-1 is designed to work with messages less than 2^64 bits long.
+ Although SHA-1 allows a message digest to be generated for messages
+ of any number of bits less than 2^64, this implementation only
+ works with messages with a length that is a multiple of the size of
+ an 8-bit character.
+
+ CHANGES
+ 2002 by Peter Zaitsev to
+ - fit to new prototypes according to MySQL standard
+ - Some optimizations
+ - All checking is now done in debug only mode
+ - More comments
+*/
+
+#include "my_global.h"
+#include "m_string.h"
+#include "sha1.h"
+
+/*
+ Define the SHA1 circular left shift macro
+*/
+
+#define SHA1CircularShift(bits,word) \
+ (((word) << (bits)) | ((word) >> (32-(bits))))
+
+/* Local Function Prototyptes */
+static void SHA1PadMessage(SHA1_CONTEXT*);
+static void SHA1ProcessMessageBlock(SHA1_CONTEXT*);
+
+
+/*
+ Initialize SHA1Context
+
+ SYNOPSIS
+ sha1_reset()
+ context [in/out] The context to reset.
+
+ DESCRIPTION
+ This function will initialize the SHA1Context in preparation
+ for computing a new SHA1 message digest.
+
+ RETURN
+ SHA_SUCCESS ok
+ != SHA_SUCCESS sha Error Code.
+*/
+
+
+const uint32 sha_const_key[5]=
+{
+ 0x67452301,
+ 0xEFCDAB89,
+ 0x98BADCFE,
+ 0x10325476,
+ 0xC3D2E1F0
+};
+
+
+int sha1_reset(SHA1_CONTEXT *context)
+{
+#ifndef DBUG_OFF
+ if (!context)
+ return SHA_NULL;
+#endif
+
+ context->Length = 0;
+ context->Message_Block_Index = 0;
+
+ context->Intermediate_Hash[0] = sha_const_key[0];
+ context->Intermediate_Hash[1] = sha_const_key[1];
+ context->Intermediate_Hash[2] = sha_const_key[2];
+ context->Intermediate_Hash[3] = sha_const_key[3];
+ context->Intermediate_Hash[4] = sha_const_key[4];
+
+ context->Computed = 0;
+ context->Corrupted = 0;
+
+ return SHA_SUCCESS;
+}
+
+
+/*
+ Return the 160-bit message digest into the array provided by the caller
+
+ SYNOPSIS
+ sha1_result()
+ context [in/out] The context to use to calculate the SHA-1 hash.
+ Message_Digest: [out] Where the digest is returned.
+
+ DESCRIPTION
+ NOTE: The first octet of hash is stored in the 0th element,
+ the last octet of hash in the 19th element.
+
+ RETURN
+ SHA_SUCCESS ok
+ != SHA_SUCCESS sha Error Code.
+*/
+
+int sha1_result(SHA1_CONTEXT *context,
+ uint8 Message_Digest[SHA1_HASH_SIZE])
+{
+ int i;
+
+#ifndef DBUG_OFF
+ if (!context || !Message_Digest)
+ return SHA_NULL;
+
+ if (context->Corrupted)
+ return context->Corrupted;
+#endif
+
+ if (!context->Computed)
+ {
+ SHA1PadMessage(context);
+ /* message may be sensitive, clear it out */
+ bzero((char*) context->Message_Block,64);
+ context->Length = 0; /* and clear length */
+ context->Computed = 1;
+ }
+
+ for (i = 0; i < SHA1_HASH_SIZE; i++)
+ Message_Digest[i] = (int8)((context->Intermediate_Hash[i>>2] >> 8
+ * ( 3 - ( i & 0x03 ) )));
+ return SHA_SUCCESS;
+}
+
+
+/*
+ Accepts an array of octets as the next portion of the message.
+
+ SYNOPSIS
+ sha1_input()
+ context [in/out] The SHA context to update
+ message_array An array of characters representing the next portion
+ of the message.
+ length The length of the message in message_array
+
+ RETURN
+ SHA_SUCCESS ok
+ != SHA_SUCCESS sha Error Code.
+*/
+
+int sha1_input(SHA1_CONTEXT *context, const uint8 *message_array,
+ unsigned length)
+{
+ if (!length)
+ return SHA_SUCCESS;
+
+#ifndef DBUG_OFF
+ /* We assume client konows what it is doing in non-debug mode */
+ if (!context || !message_array)
+ return SHA_NULL;
+ if (context->Computed)
+ return (context->Corrupted= SHA_STATE_ERROR);
+ if (context->Corrupted)
+ return context->Corrupted;
+#endif
+
+ while (length--)
+ {
+ context->Message_Block[context->Message_Block_Index++]=
+ (*message_array & 0xFF);
+ context->Length += 8; /* Length is in bits */
+
+#ifndef DBUG_OFF
+ /*
+ Then we're not debugging we assume we never will get message longer
+ 2^64 bits.
+ */
+ if (context->Length == 0)
+ return (context->Corrupted= 1); /* Message is too long */
+#endif
+
+ if (context->Message_Block_Index == 64)
+ {
+ SHA1ProcessMessageBlock(context);
+ }
+ message_array++;
+ }
+ return SHA_SUCCESS;
+}
+
+
+/*
+ Process the next 512 bits of the message stored in the Message_Block array.
+
+ SYNOPSIS
+ SHA1ProcessMessageBlock()
+
+ DESCRIPTION
+ Many of the variable names in this code, especially the single
+ character names, were used because those were the names used in
+ the publication.
+*/
+
+/* Constants defined in SHA-1 */
+static const uint32 K[]=
+{
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+};
+
+
+static void SHA1ProcessMessageBlock(SHA1_CONTEXT *context)
+{
+ int t; /* Loop counter */
+ uint32 temp; /* Temporary word value */
+ uint32 W[80]; /* Word sequence */
+ uint32 A, B, C, D, E; /* Word buffers */
+ int index;
+
+ /*
+ Initialize the first 16 words in the array W
+ */
+
+ for (t = 0; t < 16; t++)
+ {
+ index=t*4;
+ W[t] = context->Message_Block[index] << 24;
+ W[t] |= context->Message_Block[index + 1] << 16;
+ W[t] |= context->Message_Block[index + 2] << 8;
+ W[t] |= context->Message_Block[index + 3];
+ }
+
+
+ for (t = 16; t < 80; t++)
+ {
+ W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+
+ for (t = 0; t < 20; t++)
+ {
+ temp= SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 20; t < 40; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 40; t < 60; t++)
+ {
+ temp= (SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] +
+ K[2]);
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 60; t < 80; t++)
+ {
+ temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+
+ context->Message_Block_Index = 0;
+}
+
+
+/*
+ Pad message
+
+ SYNOPSIS
+ SHA1PadMessage()
+ context: [in/out] The context to pad
+
+ DESCRIPTION
+ According to the standard, the message must be padded to an even
+ 512 bits. The first padding bit must be a '1'. The last 64 bits
+ represent the length of the original message. All bits in between
+ should be 0. This function will pad the message according to
+ those rules by filling the Message_Block array accordingly. It
+ will also call the ProcessMessageBlock function provided
+ appropriately. When it returns, it can be assumed that the message
+ digest has been computed.
+
+*/
+
+void SHA1PadMessage(SHA1_CONTEXT *context)
+{
+ /*
+ Check to see if the current message block is too small to hold
+ the initial padding bits and length. If so, we will pad the
+ block, process it, and then continue padding into a second
+ block.
+ */
+
+ int i=context->Message_Block_Index;
+
+ if (i > 55)
+ {
+ context->Message_Block[i++] = 0x80;
+ bzero((char*) &context->Message_Block[i],
+ sizeof(context->Message_Block[0])*(64-i));
+ context->Message_Block_Index=64;
+
+ /* This function sets context->Message_Block_Index to zero */
+ SHA1ProcessMessageBlock(context);
+
+ bzero((char*) &context->Message_Block[0],
+ sizeof(context->Message_Block[0])*56);
+ context->Message_Block_Index=56;
+ }
+ else
+ {
+ context->Message_Block[i++] = 0x80;
+ bzero((char*) &context->Message_Block[i],
+ sizeof(context->Message_Block[0])*(56-i));
+ context->Message_Block_Index=56;
+ }
+
+ /*
+ Store the message length as the last 8 octets
+ */
+
+ context->Message_Block[56] = (int8) (context->Length >> 56);
+ context->Message_Block[57] = (int8) (context->Length >> 48);
+ context->Message_Block[58] = (int8) (context->Length >> 40);
+ context->Message_Block[59] = (int8) (context->Length >> 32);
+ context->Message_Block[60] = (int8) (context->Length >> 24);
+ context->Message_Block[61] = (int8) (context->Length >> 16);
+ context->Message_Block[62] = (int8) (context->Length >> 8);
+ context->Message_Block[63] = (int8) (context->Length);
+
+ SHA1ProcessMessageBlock(context);
+}