SHA1摘要算法实现

因为分组方式和MD5一样,但是大小端字节不一样??所以处理的时候需要对MD5分组方式作出调整。


原理:

位,字节和字

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

运算符和符号

下面的逻辑运算符都被运用于“字”(Word)
X & Y = X, Y逻辑与
X | Y = X, Y逻辑或
X ^ 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<<n)OR(X>>32-n)

在SHA1算法中,我们必须把原始消息(字符串,文件等)转换成位字符串。SHA1算法只接受位作为输入。假设我们对字符串“abc”产生 消息摘要。首先,我们将它转换成位字符串如下:
01100001 01100010 01100011
―――――――――――――
‘a’=97 ‘b’=98 ‘c’=99
这个位字符串的长度为24。下面我们需要5个步骤来计算消息摘要MAC。

补位

消息必须进行补位,以使其长度在对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了,我们可以进行下一步操作。

补长度

所谓的补长度是将 原始数据的长度补到已经进行了补 位操作的消息后面。通常用一个64位的数据来表示原始消息的长度。如果消息长度不大于2^64,那么第一个字就是0。在进行了补长度的操作以后,整个消息就变成下面这样了(16进制格式)
61626380 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000018
如果原始的消息长度超过了512,我们需要将它补成512的倍数。然后我们把整个消息分成一个一个512位的 数据块,分别处理每一个数据块,从而得到 消息摘要

使用的常量

一系列的常量字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).

使用的函数

在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).

计算消息摘要

必须使用进行了补位和补长度后的消息来计算消息摘要。计算需要两个 缓冲区,每个都由5个32位的字组成,还需要一个80个32位字的缓冲区。第一个5个字的缓冲区被标识为A,B,C,D,E。第二个5个字的缓冲区被标识为H0, H1, H2, H3, H4
。80个字的缓冲区被标识为W0, W1,..., W79
另外还需要一个一个字的TEMP缓冲区。
为了产生 消息摘要,在第3.2部分中定义的512位(16个字)的 数据块M1, M2,..., Mn
会依次进行处理,处理每个数据块Mi 包含80个步骤。
在处理所有数据块之前,缓冲区{Hi} 被初始化为下面的值(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 令
W[t] = S1(W[t-3] XOR W[t-8] XOR W[t-14] XOR W[t-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。你也可以用相似的办法来计算消息摘要。对消息进行补位的算法完全是一样的。
SHA1在许多安全协议中广为使用,包括TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被视为是 MD5(更早之前被广为使用的散列函数)的后继者。

import java.util.Scanner;

public class SHA1
{

    private final int A=0x67452301;
    private final int B=0xefcdab89;
	private final int C=0x98badcfe;
	private final int D=0x10325476;
	private final int E=0xc3d2e1f0;

	private int Atemp,Btemp,Ctemp,Dtemp,Etemp;
	
	private  void init()
	{
		Atemp = A;
		Btemp = B;
		Ctemp = C;
		Dtemp = D;
		Etemp = E;
	}
	
	private int shift(int a , int s)   //循环左移
	{
		return (a << s) | (a >>> (32 - s));
	}
	
	private int[] add(String str)		//字符串转换为int并完成添加
	{
		int num = ((str.length() + 8) / 64) + 1;
		int strByte[] = new int[num*16];
		for(int i = 0 ; i < num*16 ; i ++)
		{
			strByte[i] = 0;
		}
		int len = str.length() , i;
		for(i = 0 ; i < len ; i ++)
		{
			strByte[i>>2] |= (str.charAt(i) & 0xff )<<(((i^3) % 4)*8);    //四个字符一个int,每个字符的8位放到对应位置
		}
		strByte[i>>2] |= 0x80 << (((i^3) % 4)*8);   //最后位加1后补0
		strByte[num*16 - 1] = str.length() * 8;   //保存长度
		return strByte;	
	}
	
	private void Mainloop(int num[])		//循环加密
	{
		int w[] = new int[80];
		for(int i = 0 ; i < 16 ; i ++) w[i] = num[i];
		for(int i = 16 ; i < 80 ; i ++)
		{
			w[i] = shift(w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16], 1);
		}
		
		int F , k;  //每轮的循环运算顺序有g决定,F是决定abc的
		int a = Atemp , b = Btemp , c = Ctemp , d = Dtemp , e = Etemp;
		for(int i = 0 ; i < 80 ; i ++)  //四轮运算
		{
			if(i < 20)
			{
				F = (b & c) | (( ~b ) & d);
				k = 0x5a827999;
			}
			else if(i < 40)
			{
				F = b ^ c ^ d ;
				k = 0x6ed9eba1;
			}
			else if(i < 60)
			{
				F = (b & c) | (b & d) | ( c & d);
				k = 0x8f1bbcdc;   
			}
			else 
			{
				F = b ^ c ^ d ;
				k = 0xca62c1d6;   
			}
			int tmp = shift(a , 5) + e + w[i] + k + F;
			e = d ;
			d = c ;
			c = shift(b , 30) ;
			b = a;
			a = tmp;
		}
		Atemp = a + Atemp;					//保存当前组结果
        Btemp = b + Btemp;
        Ctemp = c + Ctemp;
        Dtemp = d + Dtemp;
        Etemp = e + Etemp;
	}
	
	private String changeHex(int a)  //转换为字符串
	{
		String str = "";
		for(int i = 0 ; i < 4 ; i ++)
		{
			str += String.format("%2s" , Integer.toHexString(((a >> (i^3)*8) % (1<<8)) & 0xff)).replace(' ', '0') ;
		}
		return str;
	}
	
	public String Md5(String str)
	{
		init();
		int strByte[] = add(str);
		for(int i = 0 ; i < strByte.length / 16 ; i ++)
		{
			int num[] = new int[16];
			for(int j = 0 ; j < 16 ; j ++)
			{
				num[j] = strByte[i*16+j];
				//System.out.println(num[j]);
			}
			Mainloop(num);
		}
		return changeHex(Atemp) + changeHex(Btemp) + changeHex(Ctemp) + changeHex(Dtemp) + changeHex(Etemp);
	}
	
	private static SHA1 instance;
	
    public static SHA1 getInstance()
    {
        if(instance == null)
        {
            instance = new SHA1();
        }
        return instance;
    }
     
    private SHA1(){};
	
	public static void main(String[] args) throws Exception
    {
    	Scanner cin = new Scanner(System.in);  
    	String str = new String();
    	while(cin.hasNext())
    	{
    		str = cin.next();
    		String str2 = SHA1.getInstance().Md5(str);
            System.out.println(str2);
    	}
    	//System.out.println(md5(str));
    }
	    
}



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值