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 = X, Y逻辑与

X \/ Y = X, Y逻辑或

X XOR Y= X, Y逻辑异或

~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<=32。Sn(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位字B,C,D并且产生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 计算消息摘要

  必须使用进行了补位和补长度后的消息来计算消息摘要。计算需要两个缓冲区,每个都由5个32位的字组成,还需要一个80个32位字的缓冲区。第一个5个字的缓冲区被标识为A,B,C,D,E。第一个5个字的缓冲区被标识为H0, H1, H2, H3, H4。80个字的缓冲区被标识为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】:2007年1月2日
*【Notice】:
*1、本文为原创技术文章,首发博客园个人站点(http://flyingbread.cnblogs.com/),转载和引用请注明作者及出处。
*2、本文必须全文转载和引用,任何组织和个人未授权不能修改任何内容,并且未授权不可用于商业。
*3、本声明为文章一部分,转载和引用必须包括在原文中。
******************************************************************************************/

SHA1算法原理(转载)相关推荐

  1. HASH和HMAC(3):SHA-1算法原理

    协议标准:https://csrc.nist.gov/CSRC/media/Publications/fips/180/2/archive/2002-08-01/documents/fips180-2 ...

  2. SMO算法原理转载+自己补充

    几何间隔: 这个意思就是超平面离数据集的点的距离. 都别装逼了,说人话是啥? 说人话就是高中几何里的"点到平面距离". 经常听到的硬间隔和软间隔是啥? 说人话: 惩罚系数C=0,硬间隔 惩罚系数C&g ...

  3. SHA-1算法c语言实现

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

  4. MySQL索引背后的数据结构及算法原理【转】

    http://blog.codinglabs.org/articles/theory-of-mysql-index.html MySQL索引背后的数据结构及算法原理[转] 摘要 本文以MySQL数据库 ...

  5. sha1原型 c语言,SHA1算法实现(C语言)

    SHA1算法实现 1. SHA1算法简介 对于长度小于2^64位的消息,SHA1产生一个160位的消息摘要.主要用于验证数据的完整性. 2. SHA1算法原理 a. 数据填充规则 对消息填充,使得其比 ...

  6. SHA1算法的编程实现

    SHA1算法的编程实现 [实验目的] [实验环境] [实验预备知识点] [实验内容] [实验步骤] [实验思考题] [实验目的] 1. 理解Hash函数的计算原理和特点: 2. 理解SHA1算法原理: ...

  7. (转载)机器学习知识点(十七)Bagging与随机森林算法原理小结

    集成学习有两个流派,一个是boosting派系,它的特点是各个弱学习器之间有依赖关系.另一种是bagging流派,它的特点是各个弱学习器之间没有依赖关系,可以并行拟合.本文就对集成学习中Bagging ...

  8. Adaboost算法原理分析和实例+代码(转载)

    [尊重原创,转载请注明出处] http://blog.csdn.net/guyuealian/article/details/70995333     本人最初了解AdaBoost算法着实是花了几天时 ...

  9. XGBoost算法原理解释(转载)

    1.XGBoost算法原理 参考文章1 参考文章2 2.代码实战 train = pd.read_csv(r"./dataset/train.csv") train.head() ...

  10. [转载] URL短网址生成算法原理

    参考链接: URL 短地址Shorteners及其Python中的API 2 短网址(Short URL),是在形式上比较短的网址,通过映射关系跳转到原有的长网址. 本文转自米扑博客:URL短网址生成 ...

最新文章

  1. windows7 64位机上配置MinGW+Codeblocks+ wxWidgets
  2. ubuntu 14.04 安装java_Ubuntu 14.04中安装Java
  3. java调用dueros_DuerOS纯java sdk 支持windows,唤醒(仅linux),技能
  4. 实验楼 “python3简明教程” 挑战三:玩转函数
  5. UILabel添加图片之富文本的简单应用
  6. 苏州宾馆管理也计算机哪个学校好,苏州十大寄宿式中学学校排名榜
  7. Hadoop精华问答 | 非大数据的项目能否用Hadoop?
  8. c语言验证寝室是否满人,寝室管理系统c语言.doc
  9. elementui可编辑单元格_ElementUI table组件实现点击单元格可编辑
  10. Linux下Hadoop分布式系统配置
  11. Linux中vi、vim命令大全
  12. HDU 2258 Continuous Same Game
  13. 不同平台安装python的方式一样吗_Python软件的正确安装方式
  14. 软考信息安全工程师好考吗?
  15. 愿码(ChainDesk.CN):EOS钱包开发 二 EOS开发环境搭建
  16. Qt线程:QThread
  17. 苹果App Store商店中国区如何改为美国区
  18. 【苹果手机登录163邮箱】
  19. mysql报1205错误
  20. [Qt] network使用post时含有中文 reply 接收报错 bad request 错误码400

热门文章

  1. 瑞友天翼提示这台计算机无法连接到服务器
  2. java毕业设计题目大全
  3. C3P0连接池 jar包 下载
  4. 7大前端项目速览!非一线城市也吃香!
  5. 苹果手机解压缩软件_「 神器 」用得贼舒服的压缩/解压缩工具
  6. java各层_java后台各个层理解
  7. 硅谷女孩火了,更该让他们开始学编程 1
  8. Windows 10 程序员计算器 HEX,DEC,OCT,BIN 的含义
  9. 清华大学计算机考研总结,2020考研清华大学计算机考研考试科目总结
  10. Android状态页切换(数据加载中,数据加载失败,空数据)