SHA1 算法加密技术核心思想

一、认知

1、在我们的平时生活中,经常会接触到一些密码,通过这些密码,能对我们的一些资产和隐私的东西做到保护作用,比如:

  • 古墓密码锁
  • 暗号:天王盖地虎,。。。。。
  • 美国的摩尔斯在 1844 年发明的摩尔斯电码,也叫摩斯密码
  • 银行,手机,游戏的账号密码

2、那么,在软件中又是用什么来实现的加密与解密的呢,作为一名程序猿,我们站在巨人的肩膀上前行,不用重复造轮子,但是我们也要知道轮子是怎么造的,今天我们就来了解一下加密与解密的核心思想。

二、常见的加密算法

  • 安全哈希算法(Secure Hash Algorithm)SHA-1
  • DES 数据加密标准
  • Base64
  • RSA 公钥加密算法

今天我们就通过 SHA-1 算法来了解一下加密与解密技术的核心思想:

在 APP 开发中,我们常见到 SHA-1 值是在签名文件中,如下图:

那么,SHA1 是什么呢,为什么 Google 要用 SHA1 作为签名文件的证书指纹呢,下面我们一起来了解SHA 算法是什么。

SHA(Secure Hash Algorithm)是安全哈希算法的简称,该算法经过加密专家多年来的发展和改进已日益完善,现在已成为公认的最安全的散列算法之一,并被广泛使用,主要适用于数字签名标准里面定义的数字签名算法。

上面的签名证书 SHA1 值是怎么得到的呢,下面以加密字符串 “abc” 为例,介绍 SHA1 加密的原理及流程。

1、将消息转换成二进制字符串

根据 ASCII 码表,字符对应的 ASCII 码为 ‘a’=97, ‘b’=98, ‘c’=99,再将其转换为二进制后为:
“abc” -> “97 98 99” -> “01100001 01100010 01100011”

2、对转换后的位字符串进行补位操作

Sha-1 算法标准规定,必须对消息摘要进行补位操作,即将输入的数据进行填充,使得数据长度对 512 求余的结果为 448,填充比特位的最高位补一个 1,其余的位补 0,如果在补位之前已经满足对 512 取模余数为 448,也要进行补位,在其后补一位1即可。
总之,补位是至少补一位,最多补 512 位,我们依然以 “abc” 为例,其补位过程如下:

  • 初始的信息摘要:01100001 01100010 01100011
  • 第一步补位: 01100001 01100010 01100011 1
  • … …
  • 补位最后一位: 01100001 01100010 01100011 10…0 (后面补了 423 个0)
  • 而后我们将补位操作后的信息摘要转换为十六进制,如下所示:
    61626380 00000000 00000000 00000000
    00000000 00000000 00000000 00000000
    00000000 00000000 00000000 00000000
    00000000 00000000
3、处理附加长度值

即补长度,就是把原始数据的长度补到已经进行补位操作的消息后面,在信息摘要后面附加 64 bit 的信息,用来表示原始信息摘要的长度,在这步操作之后,信息报文便是 512 bit 的倍数。通常来说用一个 64 位的数据表示原始消息的长度,如果消息长度不大于 2^64,那么前 32 bit 就为 0,在进行附加长度值操作后,其“abc”数据报文即变成如下形式:
61626380 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000018
因为 “abc” 占 3 个字节,即 24 位 ,换算为十六进制即为 0x18。
这样,就把整个消息分成一个个 512 位的数据块,再分别处理每个数据块,得到消息摘要

4、初始化缓存

一个 160 位 MD 缓冲区用以保存中间和最终散列函数的结果。它可以表示为 5 个 32 位的寄存器(H0,H1,H2,H3,H4)。初始化为:
H0 = 0x67452301
H1 = 0xEFCDAB89
H2 = 0x98BADCFE
H3 = 0x10325476
H4 = 0xC3D2E1F0
大端存储模式:高位数据放在低地址,低位数据放在高地址

5、计算消息摘要
  1. S 函数:循环左移操作符 Sn(x),x 是一个字,也就是 32 bit 大小的变量,n 是一个整数且 0<=n<=32。Sn(X) = (X<<n) OR (X>>32-n)
  2. 常量字 k(0)、k(1)、…k(79)
    Kt = 0x5A827999 (0 <= t <= 19)
    Kt = 0x6ED9EBA1 (20 <= t <= 39)
    Kt = 0x8F1BBCDC (40 <= t <= 59)
    Kt = 0xCA62C1D6 (60 <= t <= 79)
  3. 非线性函数
    所要用到的一系列函数,根据结果无法反推:
    Ft(b,c,d) ((b&c)|((~b)&d)) (0 <= t <= 19)
    Ft(b,c,d) (bcd) (20 <= t <= 39)
    Ft(b,c,d) ((b&c)|(b&d)|(c&d)) (40 <= t <= 59)
    Ft(b,c,d) (bcd) (60 <= t <= 79)
  4. 开始计算摘要
  • 计算需要一个缓冲区,由 5 个 32 位的字组成,还需要一个 80 个 32 位字的缓冲区。第一个 5 个字的缓冲区被标识为 A,B,C,D,E。80 个字的缓冲区被标识为 W0, W1,…, W79
  • 另外还需要一个一个字的TEMP缓冲区。
  • 为了产生消息摘要,在补好位的数据中前 16 个字的数据块 M1, M2,…, Mn
  • 会依次进行处理,处理每个数据块 Mi 包含 80 个步骤。
  • 现在开始处理 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.
6、同类算法

SHA1 SHA224 SHA256 SHA384 SHA512
MD5 HmacMD5
HmacSHA1 HmacSHA224 HmacSHA256 HmacSHA384 HmacSHA512 PBKDF2

注意:只要是哈希函数,就存在碰撞,所谓碰撞的意思是,有两个不同的数据,他们的哈希值相同(SHA1 值相同)

三、实战

废话不多说,实践才是检验真理的唯一标准,下面我们就通过代码来实现这一过程,看看结果如何:

package com.example.sha1;import org.junit.Test;/*** Created by author 2020/08/09*/public class SHA1 {//1.准备工作public static final int[] abcde = {0x67452301,0xEFCDAB89,0x98BADCFE,0x10325476,0xC3D2E1F0};//摘要数据存储用的数组(存放密文的)  20个字节*8=160;public static int[] h=new int[5];//计算过程中需要用到的临时数据存储数组public static int[] m=new int[80];//定义辅助方法//将字符转换为十六进制字符串public static String byteToHexString(byte b){//97char[] digit={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};char[] ob=new char[2];ob[0]=digit[(b>>>4)&0x0F];//9ob[1]=digit[b&0x0f];//7String s=new String(ob);//"97"return s;}//将字节数组转换为十六进制字符串public static String byteArrayToHexString(byte[] byteArray){String strDigest="";for(int i=0;i<byteArray.length;i++){strDigest+=byteToHexString(byteArray[i]);}return strDigest;}//4字节数组转换为int  i个byte合成到byteData[]中public static int byteArrayToInt(byte[] byteData,int i){//0a 0b 0c 0d  24       16       8       0//         0a000000  or  0b0000  or   0c00  or   0d//            0a0b0c0dreturn ((byteData[i]&0xff)<<24)|((byteData[i+1]&0xff)<<16)|((byteData[i+2]&0xff)<<8)|(byteData[i+3]&0xff);}//整数转换为4字节数组   int分解到byte数组中public static void intToByteArray(int intValue,byte[] byteData,int i){byteData[i]=(byte)((intValue>>>24)&0xff);byteData[i+1]=(byte)((intValue>>>16)&0xff);byteData[i+2]=(byte)((intValue>>>8)&0xff);byteData[i+3]=(byte)((intValue&0xff));}/*Ft(b,c,d)  ((b&c)|((~b)&d))    (0 <= t <= 19)Ft(b,c,d) (b^c^d)             (20 <= t <= 39)Ft(b,c,d) ((b&c)|(b&d)|(c&d))  (40 <= t <= 59)Ft(b,c,d) (b^c^d)               (60 <= t <= 79)*/public static int f1(int x,int y,int z){return (x&y)|(~x&z);}public static int f2(int x,int y,int z){return x^y^z;}public static int f3(int x,int y,int z){return (x&y)|(x&z)|(y&z);}public static int f4(int x,int y,int z){return x^y^z;}//开始逻辑//进行对原数据的补位public static byte[] byteArrayFormatData(byte[] byteData){//补0的个数int fill=0;//补位后的总位数,64的倍数int size=0;//原数据的长度int srcLength=byteData.length;//对64求余数   n%512      56数据    8长度   53int m=srcLength%64;if(m<56){fill=55-m;size=srcLength-m+64;//数据只有一块}else if(m==56){fill=63;size=srcLength+8+64;}else{fill=63-m+56;//   58    60+56  116-64=52   55-52=3size=(srcLength+64)-m+64;}//补位后生成的新数组的内容byte[] newbyte=new byte[size];System.arraycopy(byteData,0,newbyte,0,srcLength);//补1int startLocation=srcLength;newbyte[startLocation++]=(byte)0x80;//补0for(int i=0;i<fill;i++){newbyte[startLocation++]=(byte)0x00;}//处理长度的位置  字节*8=?位   512-468=64位,用来存放长度long n=(long)srcLength*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));newbyte[startLocation++]=h1;newbyte[startLocation++]=h2;newbyte[startLocation++]=h3;newbyte[startLocation++]=h4;newbyte[startLocation++]=h5;newbyte[startLocation++]=h6;newbyte[startLocation++]=h7;newbyte[startLocation++]=h8;return newbyte;}//开始计算密文 算摘要public static int process_input_bytes(byte[] byteData){System.arraycopy(abcde,0,h,0,abcde.length);//格式化数据byte[] newbyte=byteArrayFormatData(byteData);//计算有多少个大块int mCount=newbyte.length/64;//循环计算每一块的内容for(int pos=0;pos<mCount;pos++){//对每一块都进行加密计算//(1). 将 Mi 分成 16 个字 W0, W1, ... , W15,  W0 是最左边的字for(int i=0;i<16;i++){m[i]=byteArrayToInt(newbyte,(pos*64)+(i*4));}//计算encrypt();}return 20;}//n是一个整数且0<=n<=32。Sn(X) = (X<<n)OR(X>>(32-n))public static int s(int x,int i){return (x<<i)|x>>>(32-i);}public static void encrypt(){//(2). 对于 t = 16 到 79 令// Wt = S1(Wt-3 XOR Wt-8 XOR Wt- 14 XOR Wt-16).for(int t=16;t<=79;t++){m[t]=s(m[t-3]^m[t-8]^m[t-14]^m[t-16],1);}//3.令 A = H0, B = H1, C = H2, D = H3, E = H4.int[] tempabcde=new int[5];for(int i=0;i<tempabcde.length;i++){tempabcde[i]=h[i];}//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;//一共有80次操作//Kt = 0x5A827999  (0 <= t <= 19)
//        Kt = 0x6ED9EBA1 (20 <= t <= 39)
//        Kt = 0x8F1BBCDC (40 <= t <= 59)
//        Kt = 0xCA62C1D6 (60 <= t <= 79)for(int i=0;i<=19;i++){int temp=s(tempabcde[0],5)+f1(tempabcde[1],tempabcde[2],tempabcde[3])+tempabcde[4]+m[i]+0x5A827999;tempabcde[4]=tempabcde[3];tempabcde[3]=tempabcde[2];tempabcde[2]=s(tempabcde[1],30);tempabcde[1]=tempabcde[0];tempabcde[0]=temp;}for(int i=20;i<=39;i++){int temp=s(tempabcde[0],5)+f2(tempabcde[1],tempabcde[2],tempabcde[3])+tempabcde[4]+m[i]+0x6ED9EBA1;tempabcde[4]=tempabcde[3];tempabcde[3]=tempabcde[2];tempabcde[2]=s(tempabcde[1],30);tempabcde[1]=tempabcde[0];tempabcde[0]=temp;}for(int i=40;i<=59;i++){int temp=s(tempabcde[0],5)+f3(tempabcde[1],tempabcde[2],tempabcde[3])+tempabcde[4]+m[i]+0x8F1BBCDC;tempabcde[4]=tempabcde[3];tempabcde[3]=tempabcde[2];tempabcde[2]=s(tempabcde[1],30);tempabcde[1]=tempabcde[0];tempabcde[0]=temp;}for(int i=60;i<=79;i++){int temp=s(tempabcde[0],5)+f4(tempabcde[1],tempabcde[2],tempabcde[3])+tempabcde[4]+m[i]+0xCA62C1D6;tempabcde[4]=tempabcde[3];tempabcde[3]=tempabcde[2];tempabcde[2]=s(tempabcde[1],30);tempabcde[1]=tempabcde[0];tempabcde[0]=temp;}//5.令 H0 = H0 + A, H1 = H1 + B, H2 = H2 + C, H3 = H3 + D, H4 = H4 + E.for(int i=0;i<tempabcde.length;i++){h[i]=h[i]+tempabcde[i];}//完成了一次操作//清除之前的内容,开始下一个块的计算for(int i=0;i<m.length;i++){m[i]=0;}}//把已经算好的数据提供一个接口进行输入和输出public static byte[] getDigestOfBytes(byte[] byteData){process_input_bytes(byteData);byte[] digest=new byte[20];for(int i=0;i<h.length;i++){intToByteArray(h[i],digest,i*4);}return digest;}public static String getDigestOfString(byte[] byteData){return byteArrayToHexString(getDigestOfBytes(byteData));}@Testpublic void test(){//ad93ae3d06a9114b3cbb33b6433ad546f0aa9f42//378940973d2f16265b7a7f2a78a253c45d953b0bString param="abc";System.out.println("加密前:"+param);String digest=getDigestOfString(param.getBytes());System.out.println("加密后的结果:"+digest);}}

运行结果如下:

大功告成!

SHA1 算法加密技术核心思想相关推荐

  1. ASP.NET中使用MD5和SHA1算法加密

    你的主页或者你管理的网站有各种密码需要保护,把密码直接放在数据库或者文件中存在不少安全隐患,所以密码加密后存储是最常见的做法.在ASP.NET中实现加密非常容易..NET SDK中提供了CookieA ...

  2. java和c 的rsa加密算法_RSA算法签名技术Java与C++统一(加密解密结果一样)

    RSA算法签名技术Java与C++统一 (加密解密结果一样) 源代码下载地址:http://www.doczj.com/doc/64f44a94a0116c175f0e484d.html/produc ...

  3. BP神经网络的核心算法,BP神经网络的核心思想

    BP神经网络的核心问题是什么?其优缺点有哪些? . 人工神经网络,是一种旨在模仿人脑结构及其功能的信息处理系统,就是使用人工神经网络方法实现模式识别.可处理一些环境信息十分复杂,背景知识不清楚,推理规 ...

  4. 汪潮涌:AI创业落地为王,技术和算法难以成为核心壁垒

    汪潮涌:AI创业落地为王,技术和算法难以成为核心壁垒 https://mp.weixin.qq.com/s/xnvEEAWPDzIQIW-F3LjcTA 汪潮涌看来,单纯靠技术和算法的红利期已经过去. ...

  5. 【Zigbee技术入门教程-02】一图读懂ZStack协议栈的核心思想与工作机理

    [Zigbee技术入门教程-02]一图读懂ZStack协议栈的核心思想与工作机理 广东职业技术学院  欧浩源   Z-Stack协议栈是一个基于任务轮询方式的操作系统,其任务调度和资源分配由操作系统抽 ...

  6. 属性加密技术及基于属性的ABE算法的访问控制技术介绍

    属性加密技术 基于身份的加密体制简介 基于身份的加密体制可以看作一种特殊的公钥加密,它有如下特点:系统中用户的公钥可以由任意的字符串组成.这些字符串可以是用户在现实中的身份信息,如:身份证号码.用户姓 ...

  7. java sha1hash 算法_javaweb使用sha1算法登录加密的整个过程

    sha1算法还是比较潮流的算法并且可以简单使用的算法,建议新手可以选用sha1算法. 百度百科对sha1算法的解释:安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准 ( ...

  8. 【算法特训总结】计算机经典算法的核心思想及独特角度的解读

    计算机经典算法的核心思想及独特角度的解读 在1月1日新年之日开始的"算法特训"(一月一日~二月十日)终于结束了,对于这本<<算法竞赛经典>>,除了第十章(在 ...

  9. 【个人整理】一文看尽目标检测算法SSD的核心架构与设计思想

    前言:SSD(Single Shot MultiBox Detector)是大神Wei Liu在 ECCV 2016上发表的一种的目标检测算法.对于输入图像大小300x300的版本在VOC2007数据 ...

最新文章

  1. mysql-mybatis 8.0版本配置====解决could not create connection to database server.
  2. 深度学习框架PyTorch快速开发与实战
  3. 通过 Object.prototype.toString.call() 进行类型判断
  4. tomcat 部署站点时遇到的部分问题以及解决方案
  5. jQuery 1.9+ ajaxStart事件无效,无法被触发的原因。
  6. python是不是特别垃圾-【转】python是垃圾吗?
  7. NDO中的ActiveRecord 简介 2——强类型的活动记录
  8. 【已解决】wepy中使用分包加载报错
  9. mt.exe : general error c101008d: Failed to write the updated manifest to the resource of file 原因调查
  10. clojure学习记录
  11. 毛笔笔锋算法IOS版
  12. [react] ES6的语法‘...‘在React中有哪些应用?
  13. laravel 异常捕获_Laravel框架捕获各种类型错误
  14. django-自定义过滤器
  15. 优秀的电商精品素材就到优图
  16. 30 道 MySQL 面试题全放送!
  17. 通过 Android SDK Manager 安装面向 Android* 模拟器插件的英特尔® 凌动™ x86 系统映像...
  18. js判断手机端和pc端
  19. 数据结构-02-链表数据结构之双链表和循环链表
  20. 欧姆龙OMRON CP1H  PLC与台达 DOP-B触摸屏通讯

热门文章

  1. 帝国cms导入html模板,帝国CMS模板组导入导出更换模板
  2. php 图片处理羽化,ps中羽化是什么意思
  3. c语言切,c语言切换
  4. NUCLEO-F767ZI以太网初探
  5. 如何编辑二维码内容并批量生成
  6. java计算机毕业设计ssm基于Vue的二手商品交易网站z40n1(附源码、数据库)
  7. 励志共勉一句话经典语录
  8. 代理模式和Spring的AOP(持续更新)
  9. JDK动态代理(通俗易懂,小白首选)
  10. Atmel推出业内首款面向智能能源和自动化应用的IEEE 802.15.4g-2012双频段收发器