SHA1算法原理(转载)


1 SHA1算法简介

        安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。

        对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。

SHA1有如下特性:不可以从消息摘要中复原信息;两个不同的消息不会产生同样的消息摘要。

2 术语和概念

2.1(Bit),字节(Byte)和字(Word

    SHA1始终把消息当成一个位(bit)字符串来处理。本文中,一个Word)是32位,而一个字节Byte)是8位。比如,字符串“abc”可以被转换成一个位字符串:01100001 01100010 01100011。它也可以被表示成16进制字符串: 0x616263.

2.2 运算符和符号

下面的逻辑运算符都被运用于Word

X^Y = XY逻辑与

X \/ Y = XY逻辑或

X XOR Y= XY逻辑异或

~X = X逻辑取反

X+Y定义如下:

  字 X Y 代表两个整数 x y, 其中 0 <= x < 2^32 0 <= y < 2^32. 令整数z = (x + y) mod 2^32. 这时候 0 <= z < 2^32. z转换成字Z, 那么就是 Z = X + Y.

  循环左移位操作符Sn(X)X是一个字,n是一个整数,0<=n<=32Sn(X) = (X<>32-n)

X<>n是抛弃右边的n位,将各个位依次向右移动n位,然后在左边的n位填0。因此可以叫Sn(X)位循环移位运算

3 SHA1算法描述

  在SHA1算法中,我们必须把原始消息(字符串,文件等)转换成位字符串。SHA1算法只接受位作为输入。假设我们对字符串“abc”产生消息摘要。首先,我们将它转换成位字符串如下:

01100001 01100010 01100011

―――――――――――――

‘a’=97 ‘b’=98 ‘c’=99

  这个位字符串的长度为24。下面我们需要5个步骤来计算MD5

3.1 补位

  消息必须进行补位,以使其长度在对512取模以后的余数是448。也就是说,(补位后的消息长度)%512 = 448。即使长度已经满足对512取模后余数是448,补位也必须要进行。

  补位是这样进行的:先补一个1,然后再补0,直到长度满足对512取模后余数是448。总而言之,补位是至少补一位,最多补512位。还是以前面的“abc”为例显示补位的过程。

  原始信息: 01100001 01100010 01100011

  补位第一步:01100001 01100010 01100011 1

  首先补一个“1”

  补位第二步:01100001 01100010 01100011 10…..0

  然后补423“0”

  我们可以把最后补位完成后的数据用16进制写成下面的样子

61626380 00000000 00000000 00000000

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000

00000000 00000000

  现在,数据的长度是448了,我们可以进行下一步操作。

3.2 补长度

  所谓的补长度是将原始数据的长度补到已经进行了补位操作的消息后面。通常用一个64位的数据来表示原始消息的长度。如果消息长度不大于2^64,那么第一个字就是0。在进行了补长度的操作以后,整个消息就变成下面这样了(16进制格式)

61626380 00000000 00000000 00000000

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000018

  如果原始的消息长度超过了512,我们需要将它补成512的倍数。然后我们把整个消息分成一个一个512位的数据块,分别处理每一个数据块,从而得到消息摘要。

3.3 使用的常量

  一系列的常量字K(0), K(1), ... , K(79),如果以16进制给出。它们如下:

Kt = 0x5A827999 (0 <= t <= 19)

Kt = 0x6ED9EBA1 (20 <= t <= 39)

Kt = 0x8F1BBCDC (40 <= t <= 59)

Kt = 0xCA62C1D6 (60 <= t <= 79).

3.4 需要使用的函数

  在SHA1中我们需要一系列的函数。每个函数ft (0 <= t <= 79)都操作32位字BCD并且产生32位字作为输出。ft(B,C,D)可以如下定义

ft(B,C,D) = (B AND C) or ((NOT B) AND D) ( 0 <= t <= 19)

ft(B,C,D) = B XOR C XOR D (20 <= t <= 39)

ft(B,C,D) = (B AND C) or (B AND D) or (C AND D) (40 <= t <= 59)

ft(B,C,D) = B XOR C XOR D (60 <= t <= 79).

3.5 计算消息摘要

  必须使用进行了补位和补长度后的消息来计算消息摘要。计算需要两个缓冲区,每个都由532位的字组成,还需要一个8032位字的缓冲区。第一个5个字的缓冲区被标识为ABCDE。第一个5个字的缓冲区被标识为H0, H1, H2, H3, H480个字的缓冲区被标识为W0, W1,..., W79

  另外还需要一个一个字的TEMP缓冲区。

  为了产生消息摘要,在第4部分中定义的16个字的数据块M1, M2,..., Mn

  会依次进行处理,处理每个数据块Mi 包含80个步骤。

  在处理每个数据块之前,缓冲区 被初始化为下面的值(16进制)

H0 = 0x67452301

H1 = 0xEFCDAB89

H2 = 0x98BADCFE

H3 = 0x10325476

H4 = 0xC3D2E1F0.

  现在开始处理M1, M2, ... , Mn。为了处理 Mi,需要进行下面的步骤

(1). Mi 分成 16 个字 W0, W1, ... , W15, W0 是最左边的字

(2). 对于 t = 16 79 Wt = S1(Wt-3 XOR Wt-8 XOR Wt- 14 XOR Wt-16).

(3). A = H0, B = H1, C = H2, D = H3, E = H4.

(4) 对于 t = 0 79,执行下面的循环

TEMP = S5(A) + ft(B,C,D) + E + Wt + Kt;

E = D; D = C; C = S30(B); B = A; A = TEMP;

(5). H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.

  在处理完所有的 Mn, 后,消息摘要是一个160位的字符串,以下面的顺序标识

H0 H1 H2 H3 H4.

  对于SHA256,SHA384,SHA512。你也可以用相似的办法来计算消息摘要。对消息进行补位的算法完全是一样的。

4 参考文献

1: FIPS 180-1 Secure Hash Standard: http://www.itl.nist.gov/fipspubs/fip180-1.htm

2: Secure Hash Standard: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf

5 实现代码如下:

using System; 
using System.Collections; 
using System.IO; 
using System.Text;

namespace VerifySHA1
{
    public class MySHA1
    { 
        // state variables 
        private static UInt32 Message_Digest1      = 0x67452301;
        private static UInt32 Message_Digest2      = 0xEFCDAB89;
        private static UInt32 Message_Digest3      = 0x98BADCFE;
        private static UInt32 Message_Digest4      = 0x10325476;
        private static UInt32 Message_Digest5      = 0xC3D2E1F0;

        private static UInt32 SHA1CircularShift(int bits,UInt32 word) 
        {
            return ((word << bits) & 0xFFFFFFFF) | (word) >> (32-(bits));
        }

        private static void SHA1_Init()
        { 
            Message_Digest1      = 0x67452301;
            Message_Digest2      = 0xEFCDAB89;
            Message_Digest3      = 0x98BADCFE;
            Message_Digest4      = 0x10325476;
            Message_Digest5      = 0xC3D2E1F0;
        }

        private static UInt32[] SHA1_Append(byte[] input)
        { 
            int zeros=0; 
            int ones =1; 
            int size=0; 
            int n = input.Length; 
            int m = n%64; 
            if( m < 56 )
            { 
                zeros = 55-m; 
                size=n-m+64; 
            } 
            else if (m==56)
            { 
                zeros = 63; 
                ones = 1; 
                size=n+8+64; 
            } 
            else
            { 
                zeros = 63-m+56; 
                size=n+64-m+64; 
            }

            ArrayList bs = new ArrayList(input); 
            if(ones==1)
            { 
                bs.Add( (byte)0x80 ); // 0x80 = 10000000 
            } 
            for(int i=0;i<zeros;i++)
            { 
                bs.Add( (byte)0 ); 
            }

            UInt64 N = (UInt64) n * 8; 
            byte h8=(byte)(N&0xFF); 
            byte h7=(byte)((N>>8)&0xFF); 
            byte h6=(byte)((N>>16)&0xFF); 
            byte h5=(byte)((N>>24)&0xFF); 
            byte h4=(byte)((N>>32)&0xFF); 
            byte h3=(byte)((N>>40)&0xFF); 
            byte h2=(byte)((N>>48)&0xFF); 
            byte h1=(byte)(N>>56); 
            bs.Add(h1); 
            bs.Add(h2); 
            bs.Add(h3); 
            bs.Add(h4); 
            bs.Add(h5); 
            bs.Add(h6); 
            bs.Add(h7); 
            bs.Add(h8); 
            byte[] ts=(byte[])bs.ToArray(typeof(byte));

            /* Decodes input (byte[]) into output (UInt32[]). Assumes len is 
             * a multiple of 4. 
             */ 
            UInt32[] output = new UInt32[size/4]; 
            for(Int64 i=0,j=0;i<size;j++,i+=4)
            {
                UInt32 temp = 0;
                temp=temp|(((UInt32)ts[i])<<24);
                temp=temp|(((UInt32)ts[i+1])<<16);
                temp=temp|(((UInt32)ts[i+2])<<8);
                temp=temp|(((UInt32)ts[i+3]));
                output[j] = temp;
            } 
            return output; 
        } 
        private static UInt32[] SHA1_Transform(UInt32[] x)
        { 
            SHA1_Init();

            UInt32[] K = {
                             0x5A827999,
                             0x6ED9EBA1,
                             0x8F1BBCDC,
                             0xCA62C1D6
                         };
            int         t;                  
            UInt32    temp;              
            UInt32[]    W = new UInt32[80];             
            UInt32    A, B, C, D, E;  

            for(int k=0; k            {
                for(t = 0; t < 16; t++)
                {
                    W[t] = x[t+k];
                }

                for(t = 16; t < 80; t++)
                {
                    W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
                }

                A = Message_Digest1;
                B = Message_Digest2;
                C = Message_Digest3;
                D = Message_Digest4;
                E = Message_Digest5;

                for(t = 0; t < 20; t++)
                {
                    temp = SHA1CircularShift(5,A) +
                        ((B & C) | ((~B) & D)) + E + W[t] + K[0];
                    temp &= 0xFFFFFFFF;
                    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];
                    temp &= 0xFFFFFFFF;
                    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];
                    temp &= 0xFFFFFFFF;
                    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];
                    temp &= 0xFFFFFFFF;
                    E = D;
                    D = C;
                    C = SHA1CircularShift(30,B);
                    B = A;
                    A = temp;
                }

                Message_Digest1 = (Message_Digest1 + A) & 0xFFFFFFFF;
                Message_Digest2 = (Message_Digest2 + B) & 0xFFFFFFFF;
                Message_Digest3 = (Message_Digest3 + C) & 0xFFFFFFFF;
                Message_Digest4 = (Message_Digest4 + D) & 0xFFFFFFFF;
                Message_Digest5 = (Message_Digest5 + E) & 0xFFFFFFFF;
            }
        
            return new UInt32[]{Message_Digest1,Message_Digest2,Message_Digest3,Message_Digest4,Message_Digest5}; 
        } 
        public static string SHA1Array(UInt32[] input)
        { 
            StringBuilder sb = new StringBuilder();

            for(int i=0; i<input.length; i++)
            {
                sb.Append( String.Format("{0:X8}", input[i]).ToUpper() );
            }

            return sb.ToString(); 
        }

        public static string MySHA1String(string message)
        { 
            char[] c = message.ToCharArray(); 
            byte[] b = new byte[c.Length]; 
            for(int i=0;i<c.length;i++)
            { 
                b[i]=(byte)c[i]; 
            } 
            UInt32[] output = SHA1_Append( b );
            UInt32[] str = SHA1_Transform( output );
            return SHA1Array(str);
            
        } 
        public static string MySHA1File(string fileName)
        { 
            FileStream fs=File.Open(fileName,FileMode.Open,FileAccess.Read); 
            byte[] array=new byte[fs.Length]; 
            fs.Read(array,0,(int)fs.Length); 
            fs.Close(); 
            UInt32[] output = SHA1_Append( array );
            UInt32[] str = SHA1_Transform( output );
            return SHA1Array(str);
        } 
        #region Unit Test
        public static string Test(string message)
        { 
            return "\r\nSHA1 (\""+message+"\") = " + MySHA1String(message); 
        } 
        public static string TestSuite()
        {     
            string s = ""; 
            s+=Test(""); 
            s+=Test("a"); 
            s+=Test("abc"); 
            s+=Test("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); 
            s+=Test("abcdefghijklmnopqrstuvwxyz"); 
            s+=Test("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 
            s+=Test("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); 
            //        StringBuilder sb = new StringBuilder();
            //        for(int i=0; i<1000000; i++)
            //            sb.Append("a");
            //        s+=Test(sb.ToString());

            return s;     
        }

        public static void Main()
        {
            Console.WriteLine(MySHA1.TestSuite());
            Console.ReadLine();
        }
        #endregion
    } 
}


/******************************************************************************************
*Author】:flyingbread
*Date】:200712
*Notice】:
*1、本文为原创技术文章,首发博客园个人站点(http://flyingbread.cnblogs.com/),转载和引用请注明作者及出处。
*2、本文必须全文转载和引用,任何组织和个人未授权不能修改任何内容,并且未授权不可用于商业。
*3、本声明为文章一部分,转载和引用必须包括在原文中。
******************************************************************************************/

 


  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SHA-1算法是一种数据加密算法,它可以将输入的明文转换为一段固定长度的密文,也称为散列值或摘要信息。关于SHA-1算法的重复性问题,指的是是否可能存在两个不同的输入,但经过SHA-1算法加密后得到相同的输出。根据目前的密码学研究,SHA-1算法存在碰撞问题,即可以找到两个不同的输入,但它们的SHA-1摘要值相同。这意味着SHA-1算法不具备完全的抗碰撞性。 由于SHA-1算法的摘要长度较长(160位),从理论上讲,找到两个具有相同摘要的输入的可能性非常小,需要进行大量的计算。然而,随着计算能力的增加和密码学研究的进展,对SHA-1算法的攻击方法也在不断改进。目前已经有实际的攻击方法能够在合理的时间内找到SHA-1的碰撞。 因此,为了确保数据的安全性,推荐使用更安全的哈希算法,如SHA-256或SHA-3,这些算法具有更长的摘要长度和更好的抗碰撞性。同时,在实际应用中,应始终考虑使用多重加密方法和密钥管理来增加数据的安全性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [【图解SHA1杂凑算法SHA1杂凑算法的Python实现保姆级教程 | 物联网安全 | 信息安全](https://blog.csdn.net/Magic_Zsir/article/details/124217707)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [c语言实验杂凑算法SHA-1,SHA-1加密算法](https://blog.csdn.net/weixin_39593523/article/details/117140405)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值