sha1.cpp

Go to the documentation of this file.
00001 /* $Id: sha1.cpp 23842 2008-02-16 08:47:16Z mordante $ */
00002 /*
00003    Copyright (C) 2007 - 2008 by Benoit Timbert <benoit.timbert@free.fr>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 //! @file sha1.cpp
00016 //! Secure Hash Algorithm 1 (SHA-1).
00017 //! Used to checksum the game-config / cache.
00018 
00019 /* This is supposed to be an implementation of the
00020    Secure Hash Algorithm 1 (SHA-1)
00021 
00022    Check RFC 3174 for details about the algorithm.
00023 
00024    Currently this implementation might produce different results on little-
00025    and big-endian machines, but for our current usage, we don't care :)
00026 */
00027 
00028 #include "sha1.hpp"
00029 
00030 #include <iomanip>
00031 #include <sstream>
00032 
00033 #define sha_rotl(n,x)       ( ((x) << (n)) | ((x) >> (32-(n))) )
00034 #define sha_ch(x,y,z)       ( ((x) & (y)) | ((!(x)) & (z)) )
00035 #define sha_parity(x,y,z)   ( (x) ^ (y) ^ (z) )
00036 #define sha_maj(x,y,z)      ( ((x) & (y)) | ((x) & (z)) | ((y) & (z)) )
00037 
00038 //! Display the hash
00039 std::string sha1_hash::display() {
00040     std::stringstream s;
00041     s << std::hex << std::setfill('0') << std::setw(8) << H0;
00042     s << std::hex << std::setfill('0') << std::setw(8) << H1;
00043     s << std::hex << std::setfill('0') << std::setw(8) << H2;
00044     s << std::hex << std::setfill('0') << std::setw(8) << H3;
00045     s << std::hex << std::setfill('0') << std::setw(8) << H4;
00046     return s.str();
00047 }
00048 
00049 //! Make a hash from a string
00050 sha1_hash::sha1_hash(const std::string& str)
00051 : H0(0x67452301), H1(0xefcdab89), H2(0x98badcfe), H3(0x10325476), H4(0xc3d2e1f0)
00052 {
00053     Uint8 block[64];
00054 
00055     int bytes_left = str.size();
00056     Uint32 ssz = bytes_left * 8; // string length in bits
00057 
00058     std::stringstream iss (str, std::stringstream::in);
00059     // cut our string in 64 bytes blocks then process it
00060     while (bytes_left > 0) {
00061         iss.read(reinterpret_cast<char*>(block), 64);
00062         if (bytes_left <= 64) { // if it's the last block, pad it
00063             if (bytes_left < 64) {
00064                 block[bytes_left]= 0x80; // add a 1 bit right after the end of the string
00065             }
00066             int i;
00067             for (i = 63; i > bytes_left; i--) {
00068                 block[i]=0; // pad our block with zeros
00069             }
00070             if (bytes_left < 60) { // enough space to store the length
00071                 // put the length at the end of the block
00072                 block[60] = ssz >> 24;
00073                 block[61] = ssz >> 16;
00074                 block[62] = ssz >> 8;
00075                 block[63] = ssz;
00076             } else { // not enough space for the zeros => we need a new block
00077                 next(block);
00078                 // new block
00079                 for (i = 0; i < 60 ; i++) {
00080                     block[i]=0; // pad our block with zeros
00081                 }
00082                 if (bytes_left == 64) {
00083                     block[0]= 0x80; // add a 1 bit right after the end of the string = beginning of our new block
00084                 }
00085                 // put the length at the end of the block
00086                 block[60] = ssz >> 24;
00087                 block[61] = ssz >> 16;
00088                 block[62] = ssz >> 8;
00089                 block[63] = ssz;
00090             }
00091         }
00092         next(block);
00093         bytes_left -= 64;
00094     }
00095 }
00096 
00097 //! Process the next 512 bits block
00098 void sha1_hash::next(Uint8 block[64]) {
00099     Uint32 W[80];
00100     Uint32 A, B, C, D, E, T;
00101     int i;
00102 
00103     A = H0;
00104     B = H1;
00105     C = H2;
00106     D = H3;
00107     E = H4;
00108     for (i = 0; i < 16; i++) {
00109         W[i]= (block[4 * i] << 24) | (block[4 * i + 1] << 16) | (block[4 * i + 2] << 8) | block[4 * i + 3];
00110     }
00111     for (; i < 80; i++) {
00112         W[i]=sha_rotl(1, W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]);
00113     }
00114     for (i = 0; i < 20; i++) {
00115         T = sha_rotl(5,A) + sha_ch(B,C,D) + E + W[i] + 0x5a827999;
00116         E = D;
00117         D = C;
00118         C = sha_rotl(30,B);
00119         B = A;
00120         A = T;
00121     }
00122     for (; i < 40; i++) {
00123         T = sha_rotl(5,A) + sha_parity(B,C,D) + E + W[i] + 0x6ed9eba1;
00124         E = D;
00125         D = C;
00126         C = sha_rotl(30,B);
00127         B = A;
00128         A = T;
00129     }
00130     for (; i < 60; i++) {
00131         T = sha_rotl(5,A) + sha_maj(B,C,D) + E + W[i] + 0x8f1bbcdc;
00132         E = D;
00133         D = C;
00134         C = sha_rotl(30,B);
00135         B = A;
00136         A = T;
00137     }
00138     for (; i < 80; i++) {
00139         T = sha_rotl(5,A) + sha_parity(B,C,D) + E + W[i] + 0xca62c1d6;
00140         E = D;
00141         D = C;
00142         C = sha_rotl(30,B);
00143         B = A;
00144         A = T;
00145     }
00146     H0 += A;
00147     H1 += B;
00148     H2 += C;
00149     H3 += D;
00150     H4 += E;
00151 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs