adc转换的结果存储在哪,ad转换程序
一、传感器***ad转换程序
此程序是我做单片机课程设计的程序,PROTEL原理图在附件里
程序经过了实验的测试,没有任何问题。
一设计要求:
1.以8031为主控器组成A/D,D/A转换系统。
2.对任意波形的脉冲信号进行A/D转换后进入数据存储器,要求能够存储5~10个周波,然后定时将数据经D/A转换输出示波器显示。
3.采样的频率可由键盘有级调节。
二课程设计条件:
硬件:个人PC一台,8051单片机仿真头一个,89S51单片机一个,ADC0809芯片一块,DAC0832芯片一块,7402一个,LM358一片,按键开关5个,电阻电容若干,6M晶振一个,稳压电源,函数信号发生器,及示波器个一个
软件:PC机WINDOWS*作系统,KEIL单片机仿真调试软件
三设计思想:
通过ADC0809将正弦波模拟信号按照一定的频率进行采样,频率由键盘进行串级控制,转换成数字量,然后存储到8155的RAM里面,再将数据输出到DAC0832,将数字量转化成模拟量,经过LM358将信号放大,送到示波器终端循环显示出来
BUFFRE EQU 31H;采样频率设置单元
BUFRAM EQU 7E00H;8155RAM首地址
BUFADC EQU 0FD1FH;0809启动地址
BUFDAC EQU 0BFFH;0832启动地址
K1 EQU P1.4;四个频率选择按键
K2 EQU P1.5
K3 EQU P1.6
K4 EQU P1.7
ORG 0000H
LJMP START
ORG 0030H
START: MOV R4,#02;由于8155的复位时间比8051慢,所以在对8155初始化之前必须有延时
DEL11:MOV R6,#200;延时为021s的倍
DEL21:MOV R7,#126
DEL31:DJNZ R7,DEL31
DJNZ R6,DEL21
DJNZ R5,DEL11
MOV DPTR,#7FF8H; 8155初始化
MOV A,#00H;写入命令字
MOVX@DPTR,A
MOV R0,#0FAH
MOV DPTR,#BUFRAM
LOOP:MOVX@DPTR,A;对8155RAM清零
INC DPTR
DJNZ R0,LOOP
FRESET:MOV P1,#0FFH;准备读取P1口状态
JB K1,NEXT1;依次判断按下了哪一个按键
MOV BUFFRE,#02H;送相应的频率设置到31内存单元
LJMP INPUT
NEXT1:JB K2,NEXT2
MOV BUFFRE,#04H
LJMP INPUT
NEXT2:JB K3,NEXT3
MOV BUFFRE,#08H
LJMP INPUT
NEXT3:JB K4,NEXT4
MOV BUFFRE,#06H
LJMP REALIO;如果是K4按下,则进行实时输入输出
NEXT4:LJMP FRESET;循环等待按键按下
INPUT:; A/D采样程序
MOV R0,#0FAH;共采集250个数据
MOV DPTR,#BUFRAM; 8155RAM首地址
LOOP1:PUSH DPL;先保存次地址
PUSH DPH
MOV DPTR,#BUFADC; 0809启动地址
MOV A,#00H
MOVX@DPTR,A;启动0809 A/D转换开始
NOP;一定时间延时
NOP
WAIT:JB P1.0,WAIT;等待转换结束
MOVX A,@DPTR;读取转换结果
POP DPH
POP DPL;恢复RAM地址
MOVX@DPTR,A;保存数据至8155RAM
INC DPTR;RAM地址加一,指向下一个存储单元
ACALL DELAY;延时,即以一定频率采样
DJNZ R0,LOOP1; 250个数据是否采集完成,否则继续
OUTPUT:; D/A转换模块
MOV R1,#0FAH;250个数据
MOV DPTR,#BUFRAM; 8155RAM首地址
LOOP2: PUSH DPL;保存此地址
PUSH DPH
MOVX A,@DPTR;将数据输出到A中
MOV DPTR,#BUFDAC; 0832地址
MOVX@DPTR,A;将数据输出进行D/A转换
NOP;为了与采样频率一直,设定一定延时
NOP
POP DPH;恢复RAM地址
POP DPL
INC DPTR;指向下一个要转换的数据单元
ACALL DELAY;与采样相同延时
DJNZ R1,LOOP2;直道转换完成
WAIT2:JNB K4,NEXT
LJMP OUTPUT;循环显示输出结果
NEXT:LJMP REALIO
DELAY:MOV R5,BUFFRE;延时程序,通过R5的不同,改变延时时间,从而改变
DEL1:MOV R6,#2;延时为0.001s的倍
DEL2:MOV R7,#126
DEL3:DJNZ R7,DEL3
DJNZ R6,DEL2
DJNZ R5,DEL1
RET
REALIO:;实时显示程序
MOV DPTR,#BUFADC
MOV A,#00H
MOVX@DPTR,A
NOP
NOP
WAIT1:JB P1.0,WAIT1
MOVX A,@DPTR
MOV DPTR,#BUFDAC
MOVX@DPTR,A
NOP
NOP
FRESET1:MOV P1,#0FFH;准备读取P1口状态
JB K1,NEXT11;依次判断按下了哪一个按键
MOV BUFFRE,#02H;送相应的频率设置到31内存单元
LJMP INPUT
NEXT11:JB K2,NEXT12
MOV BUFFRE,#04H
LJMP INPUT
NEXT12:JB K3,NEXT13
MOV BUFFRE,#08H
LJMP INPUT
NEXT13:LJMP REALIO
END
八使用说明
1.上电复位或者按键复位后,程序开始运行后,等待K1-K4的按键被按下,根据按下的键值作不同的处理。
2.如果被按下的是K1-K3键,则根据按下的键分别设置不同的采样频率,然后开始进行A/D转换进行信号的采样,再存储至8155的RAM中,如果存储完了250个数据,则自动开始进行数据的D/A输出,在示波器上可以看到相应的波形,数据是循环输出的,所以可以一直看到数据输出!
3.如果是按键K4被按下,则进行的是实时的采样输入输出,即将信号通过ADC0809采样进来,不保存至8155的RAM中,就立即送到DAC0832输出到示波器显示,这样的信号基本上就是原来的信号波形。
4.在K1-K3按下后正常的采样,存储,输出过程中,也可以按下K4键而转到实时的输入输出程序,便于将采样数据和原数据进行对照。
5.在实时的输入输出时,也可以同过按下K1-K3键,立即切换到原来的一定频率采样,存储,输出过程。
6.硬件设计上还有一个复位键,可以对程序进行按键复位(汇编,已经实验通过)
简单的A/D,D/A转换程序
此程序是我做单片机课程设计的程序,PROTEL原理图在附件里
程序经过了实验的测试,没有任何问题,
一设计要求:
1.以8031为主控器组成A/D,D/A转换系统。
2.对任意波形的脉冲信号进行A/D转换后进入数据存储器,要求能够存储5~10个周波,然后定时将数据经D/A转换输出示波器显示。
3.采样的频率可由键盘有级调节。
二课程设计条件:
硬件:个人PC一台,8051单片机仿真头一个,89S51单片机一个,ADC0809芯片一块,DAC0832芯片一块,7402一个,LM358一片,按键开关5个,电阻电容若干,6M晶振一个,稳压电源,函数信号发生器,及示波器个一个
软件:PC机WINDOWS*作系统,KEIL单片机仿真调试软件
三设计思想:
通过ADC0809将正弦波模拟信号按照一定的频率进行采样,频率由键盘进行串级控制,转换成数字量,然后存储到8155的RAM里面,再将数据输出到DAC0832,将数字量转化成模拟量,经过LM358将信号放大,送到示波器终端循环显示出来
BUFFRE EQU 31H;采样频率设置单元
BUFRAM EQU 7E00H;8155RAM首地址
BUFADC EQU 0FD1FH;0809启动地址
BUFDAC EQU 0BFFH;0832启动地址
K1 EQU P1.4;四个频率选择按键
K2 EQU P1.5
K3 EQU P1.6
K4 EQU P1.7
ORG 0000H
LJMP START
ORG 0030H
START: MOV R4,#02;由于8155的复位时间比8051慢,所以在对8155初始化之前必须有延时
DEL11:MOV R6,#200;延时为021s的倍
DEL21:MOV R7,#126
DEL31:DJNZ R7,DEL31
DJNZ R6,DEL21
DJNZ R5,DEL11
MOV DPTR,#7FF8H; 8155初始化
MOV A,#00H;写入命令字
MOVX@DPTR,A
MOV R0,#0FAH
MOV DPTR,#BUFRAM
LOOP:MOVX@DPTR,A;对8155RAM清零
INC DPTR
DJNZ R0,LOOP
FRESET:MOV P1,#0FFH;准备读取P1口状态
JB K1,NEXT1;依次判断按下了哪一个按键
MOV BUFFRE,#02H;送相应的频率设置到31内存单元
LJMP INPUT
NEXT1:JB K2,NEXT2
MOV BUFFRE,#04H
LJMP INPUT
NEXT2:JB K3,NEXT3
MOV BUFFRE,#08H
LJMP INPUT
NEXT3:JB K4,NEXT4
MOV BUFFRE,#06H
LJMP REALIO;如果是K4按下,则进行实时输入输出
NEXT4:LJMP FRESET;循环等待按键按下
INPUT:; A/D采样程序
MOV R0,#0FAH;共采集250个数据
MOV DPTR,#BUFRAM; 8155RAM首地址
LOOP1:PUSH DPL;先保存次地址
PUSH DPH
MOV DPTR,#BUFADC; 0809启动地址
MOV A,#00H
MOVX@DPTR,A;启动0809 A/D转换开始
NOP;一定时间延时
NOP
WAIT:JB P1.0,WAIT;等待转换结束
MOVX A,@DPTR;读取转换结果
POP DPH
POP DPL;恢复RAM地址
MOVX@DPTR,A;保存数据至8155RAM
INC DPTR;RAM地址加一,指向下一个存储单元
ACALL DELAY;延时,即以一定频率采样
DJNZ R0,LOOP1; 250个数据是否采集完成,否则继续
OUTPUT:; D/A转换模块
MOV R1,#0FAH;250个数据
MOV DPTR,#BUFRAM; 8155RAM首地址
LOOP2: PUSH DPL;保存此地址
PUSH DPH
MOVX A,@DPTR;将数据输出到A中
MOV DPTR,#BUFDAC; 0832地址
MOVX@DPTR,A;将数据输出进行D/A转换
NOP;为了与采样频率一直,设定一定延时
NOP
POP DPH;恢复RAM地址
POP DPL
INC DPTR;指向下一个要转换的数据单元
ACALL DELAY;与采样相同延时
DJNZ R1,LOOP2;直道转换完成
WAIT2:JNB K4,NEXT
LJMP OUTPUT;循环显示输出结果
NEXT:LJMP REALIO
DELAY:MOV R5,BUFFRE;延时程序,通过R5的不同,改变延时时间,从而改变
DEL1:MOV R6,#2;延时为0.001s的倍
DEL2:MOV R7,#126
DEL3:DJNZ R7,DEL3
DJNZ R6,DEL2
DJNZ R5,DEL1
RET
REALIO:;实时显示程序
MOV DPTR,#BUFADC
MOV A,#00H
MOVX@DPTR,A
NOP
NOP
WAIT1:JB P1.0,WAIT1
MOVX A,@DPTR
MOV DPTR,#BUFDAC
MOVX@DPTR,A
NOP
NOP
FRESET1:MOV P1,#0FFH;准备读取P1口状态
JB K1,NEXT11;依次判断按下了哪一个按键
MOV BUFFRE,#02H;送相应的频率设置到31内存单元
LJMP INPUT
NEXT11:JB K2,NEXT12
MOV BUFFRE,#04H
LJMP INPUT
NEXT12:JB K3,NEXT13
MOV BUFFRE,#08H
LJMP INPUT
NEXT13:LJMP REALIO
END
八使用说明
1.上电复位或者按键复位后,程序开始运行后,等待K1-K4的按键被按下,根据按下的键值作不同的处理。
2.如果被按下的是K1-K3键,则根据按下的键分别设置不同的采样频率,然后开始进行A/D转换进行信号的采样,再存储至8155的RAM中,如果存储完了250个数据,则自动开始进行数据的D/A输出,在示波器上可以看到相应的波形,数据是循环输出的,所以可以一直看到数据输出!
3.如果是按键K4被按下,则进行的是实时的采样输入输出,即将信号通过ADC0809采样进来,不保存至8155的RAM中,就立即送到DAC0832输出到示波器显示,这样的信号基本上就是原来的信号波形。
4.在K1-K3按下后正常的采样,存储,输出过程中,也可以按下K4键而转到实时的输入输出程序,便于将采样数据和原数据进行对照。
5.在实时的输入输出时,也可以同过按下K1-K3键,立即切换到原来的一定频率采样,存储,输出过程。
6.硬件设计上还有一个复位键,可以对程序进行按键复位
二、影响adc和dac转换性能的指标有哪些
影响adc和dac转换性能的指标有转换精度和转换速度。
1、电源抑制比
对于高质量的D/A转换器,要求开关电路及运算放大器所用的电源电压发生变化时,对输出电压影响极小。通常把满量程电压变化的百分数与电源电压变化的百分数之比称为电源抑制比。
2、工作温度范围
一般情况下,影响D/A转换精度的主要环境和工作条件因素是温度和电源电压变化。由于工作温度会对运算放大器加权电阻网络等产生影响,所以只有在一定的工作范围内才能保证额定精度指标。
较好的D/A转换器的工作温度范围在-40℃~85℃之间,较差的D/A转换器的工作温度范围在0℃~70℃之间。多数器件其静、动态指标均。
在25℃的工作温度下测得的,工作温度对各项精度指标的影响用温度系数来描述,如失调温度系数、增益温度系数、微分线性误差温度系数等。
D/A转换器的主要性能指标:
1、分辨率
分辨率是指输入数字量的低有效位(LSB)发生变化时,所对应的输出模拟量(电压或电流)的变化量。它反映了输出模拟量的小变化值。
分辨率与输入数字量的位数有确定的关系,可以表示成FS/2^n。FS表示满量程输入值,n为二进制位数。对于5V的满量程,采用8位的DAC时,分辨率为5V/256=19.5mV;当采用12位的DAC时,分辨率则为5V/4096=1.22mV。显然,位数越多分辨率就越高。
2、线性度
线性度(也称非线性误差)是实际转换特性曲线与理想直线特性之间的大偏差。常以相对于满量程的百分数表示。如±1%是指实际输出值与理论值之差在满刻度的±1%以内。
3、绝对精度和相对精度
绝对精度(简称精度)是指在整个刻度范围内,任一输入数码所对应的模拟量实际输出值与理论值之间的大误差。
绝对精度是由DAC的增益误差(当输入数码为全1时,实际输出值与理想输出值之差)、零点误差(数码输入为全0时,DAC的非零输出值)、非线性误差和噪声等引起的。绝对精度(即大误差)应小于1个LSB。
相对精度与绝对精度表示同一含义,用大误差相对于满刻度的百分比表示。
三、如何安全的存储用户的密码
保护密码好的的方式就是使用带盐的密码hash(salted password hashing).对密码进行hash*作是一件很简单的事情,但是很多人都犯了错。接下来我希望可以详细的阐述如何恰当的对密码进行hash,以及为什么要这样做。
重要提醒
如果你打算自己写一段代码来进行密码hash,那么赶紧停下吧。这样太容易犯错了。这个提醒适用于每一个人,不要自己写密码的hash算法!关于保存密码的问题已经有了成熟的方案,那就是使用phpass或者本文提供的源码。
什么是hash
hash("hello")= 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo")= 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
hash("waltz")= c0e81794384491161f1777c232bc6bd9ec38f616560b120fda8e90f383853542
Hash算法是一种单向的函数。它可以把任意数量的数据转换成固定长度的“指纹”,这个过程是不可逆的。而且只要输入发生改变,哪怕只有一个**t,输出的hash值也会有很大不同。这种特性恰好合适用来用来保存密码。因为我们希望使用一种不可逆的算法来加密保存的密码,同时又需要在用户登陆的时候验证密码是否正确。
在一个使用hash的账号系统中,用户注册和认证的大致流程如下:
1,用户创建自己的账号
2,用户密码经过hash*作之后存储在数据库中。没有任何明文的密码存储在服务器的硬盘上。
3,用户登陆的时候,将用户输入的密码进行hash*作后与数据库里保存的密码hash值进行对比。
4,如果hash值完全一样,则认为用户输入的密码是正确的。否则就认为用户输入了无效的密码。
5,每次用户尝试登陆的时候就重复步骤3和步骤4。
在步骤4的时候不要告诉用户是账号还是密码错了。只需要显示一个通用的提示,比如账号或密码不正确就可以了。这样可以防止攻击者枚举有效的用户名。
还需要注意的是用来保护密码的hash函数跟数据结构课上见过的hash函数不完全一样。比如实现hash表的hash函数设计的目的是快速,但是不够安全。只有加密hash函数(cryptographic hash functions)可以用来进行密码的hash。这样的函数有SHA256, SHA512, RipeMD, WHIRLPOOL等。
一个常见的观念就是密码经过hash之后存储就安全了。这显然是不正确的。有很多方式可以快速的从hash恢复明文的密码。还记得那些md5破解网站吧,只需要提交一个hash,不到一秒钟就能知道结果。显然,单纯的对密码进行hash还是远远达不到我们的安全需求。下一部分先讨论一下破解密码hash,获取明文常见的手段。
如何破解hash
字典和暴力破解攻击(Dictionary and Brute Force Attacks)
常见的破解hash手段就是猜测密码。然后对每一个可能的密码进行hash,对比需要破解的hash和猜测的密码hash值,如果两个值一样,那么之前猜测的密码就是正确的密码明文。猜测密码攻击常用的方式就是字典攻击和暴力攻击。
Dictionary Attack
Trying apple: failed
Trying blueberry: failed
Trying justinbeiber: failed
...
Trying letmein: failed
Trying s3cr3t: success!
字典攻击是将常用的密码,单词,短语和其他可能用来做密码的字符串放到一个文件中,然后对文件中的每一个词进行hash,将这些hash与需要破解的密码hash比较。这种方式的成功率取决于密码字典的大小以及字典的是否合适。
Brute Force Attack
Trying aaaa: failed
Trying aaab: failed
Trying aaac: failed
...
Trying acdb: failed
Trying acdc: success!
暴力攻击就是对于给定的密码长度,尝试每一种可能的字符组合。这种方式需要花费大量的计算机时间。但是理论上只要时间足够,后密码一定能够破解出来。只是如果密码太长,破解花费的时间就会大到无法承受。
目前没有方式可以阻止字典攻击和暴力攻击。只能想办法让它们变的低效。如果你的密码hash系统设计的是安全的,那么破解hash唯一的方式就是进行字典或者暴力攻击了。
查表破解(Lookup Tables)
对于特定的hash类型,如果需要破解大量hash的话,查表是一种非常有效而且快速的方式。它的理念就是预先计算(pre-compute)出密码字典中每一个密码的hash。然后把hash和对应的密码保存在一个表里。一个设计良好的查询表结构,即使存储了数十亿个hash,每秒钟仍然可以查询成百上千个hash。
如果你想感受下查表破解hash的话可以尝试一下在CraskStation上破解下下面的sha256 hash。
c11083b4b0a7743af748c85d343dfee9fbb8b2576c05f3a7f0d632b0926aadfc
08eac03b80adc33dc7d8fbe44b7c7b05d3a2c511166bdb43fcb710b03ba919e7
e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904
5206b8b8a996cf5320cb12ca91c7b790fba9f030408efe83ebb83548dc3007bd
反向查表破解(Reverse Lookup Tables)
Searching for hash(apple) in users' hash list...: Matches [alice3, 0bob0, charles8]
Searching for hash(blueberry) in users' hash list...: Matches [usr10101, timmy, john91]
Searching for hash(letmein) in users' hash list...: Matches [wilson10, dragonslayerX, joe1984]
Searching for hash(s3cr3t) in users' hash list...: Matches [bruce19, knuth1337, john87]
Searching for hash(z@29hjja) in users' hash list...: No users used this password
这种方式可以让攻击者不预先计算一个查询表的情况下同时对大量hash进行字典和暴力破解攻击。
首先,攻击者会根据获取到的数据库数据制作一个用户名和对应的hash表。然后将常见的字典密码进行hash之后,跟这个表的hash进行对比,就可以知道用哪些用户使用了这个密码。这种攻击方式很有效果,因为通常情况下很多用户都会有使用相同的密码。
彩虹表(Rainbow Tables)
彩虹表是一种使用空间换取时间的技术。跟查表破解很相似。只是它牺牲了一些破解时间来达到更小的存储空间的目的。因为彩虹表使用的存储空间更小,所以单位空间就可以存储更多的hash。彩虹表已经能够破解8位长度的任意md5hash。彩虹表具体的原理可以参考
下一章节我们会讨论一种叫做“盐”(salting)的技术。通过这种技术可以让查表和彩虹表的方式无法破解hash。
加盐(Adding Salt)
hash("hello")= 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hello"+"QxLUF1bgIAdeQX")= 9e209040c863f84a31e719795b2577523954739fe5ed3b58a75cff2127075ed1
hash("hello"+"bv5PehSMfV11Cd")= d1d3ec2e6f20fd420d50e2642992841d8338a314b8ea157c9e18477aaef226ab
hash("hello"+"YYLmfY6IehjZMQ")= a49670c3c18b9e079b9cfaf51634f563dc8ae3070db2c4a8544305df1b60f007
查表和彩虹表的方式之所以有效是因为每一个密码的都是通过同样的方式来进行hash的。如果两个用户使用了同样的密码,那么一定他们的密码hash也一定相同。我们可以通过让每一个hash随机化,同一个密码hash两次,得到的不同的hash来避免这种攻击。
具体的*作就是给密码加一个随即的前缀或者后缀,然后再进行hash。这个随即的后缀或者前缀成为“盐”。正如上面给出的例子一样,通过加盐,相同的密码每次hash都是完全不一样的字符串了。检查用户输入的密码是否正确的时候,我们也还需要这个盐,所以盐一般都是跟hash一起保存在数据库里,或者作为hash字符串的一部分。
盐不需要保密,只要盐是随机的话,查表,彩虹表都会失效。因为攻击者无法事先知道盐是什么,也就没有办法预先计算出查询表和彩虹表。如果每个用户都是使用了不同的盐,那么反向查表攻击也没法成功。
下一节,我们会介绍一些盐的常见的错误实现。
错误的方式:短的盐和盐的复用
常见的错误实现就是一个盐在多个hash中使用或者使用的盐很短。
盐的复用(Salt Reuse)
不管是将盐硬编码在程序里还是随机一次生成的,在每一个密码hash里使用相同的盐会使这种防御方法失效。因为相同的密码hash两次得到的结果还是相同的。攻击者就可以使用反向查表的方式进行字典和暴力攻击。只要在对字典中每一个密码进行hash之前加上这个固定的盐就可以了。如果是流行的程序的使用了硬编码的盐,那么也可能出现针对这种程序的这个盐的查询表和彩虹表,从而实现快速破解hash。
用户每次创建或者修改密码一定要使用一个新的随机的盐
短的盐
如果盐的位数太短的话,攻击者也可以预先制作针对所有可能的盐的查询表。比如,3位ASCII字符的盐,一共有95x95x95= 857,375种可能性。看起来好像很多。假如每一个盐制作一个1MB的包含常见密码的查询表,857,375个盐才是837GB。现在买个1TB的硬盘都只要几百块而已。
基于同样的理由,千万不要用用户名做为盐。虽然对于每一个用户来说用户名可能是不同的,但是用户名是可预测的,并不是完全随机的。攻击者完全可以用常见的用户名作为盐来制作查询表和彩虹表破解hash。
根据一些经验得出来的规则就是盐的大小要跟hash函数的输出一致。比如,SHA256的输出是256**ts(32bytes),盐的长度也应该是32个字节的随机数据。
错误的方式:双重hash和古怪的hash函数
这一节讨论另外一个常见的hash密码的误解:古怪的hash算法组合。人们可能解决的将不同的hash函数组合在一起用可以让数据更安全。但实际上,这种方式带来的效果很微小。反而可能带来一些互通性的问题,甚至有时候会让hash更加的不安全。本文一开始就提到过,永远不要尝试自己写hash算法,要使用专家们设计的标准算法。有些人会觉得通过使用多个hash函数可以降低计算hash的速度,从而增加破解的难度。通过减慢hash计算速度来防御攻击有更好的方法,这个下文会详细介绍。
下面是一些网上找到的古怪的hash函数组合的样例。
md5(sha1(password))
md5(md5(salt)+ md5(password))
sha1(sha1(password))
sha1(str_rot13(password+ salt))
md5(sha1(md5(md5(password)+ sha1(password))+ md5(password)))
不要使用他们!
注意:这部分的内容其实是存在争议的!我收到过大量邮件说组合hash函数是有意义的。因为如果攻击者不知道我们用了哪个函数,就不可能事先计算出彩虹表,并且组合hash函数需要更多的计算时间。
攻击者如果不知道hash算法的话自然是无法破解hash的。但是考虑到Kerckhoffs’s principle,攻击者通常都是能够接触到源码的(尤其是免费软件和开源软件)。通过一些目标系统的密码–hash对应关系来逆向出算法也不是非常困难。
如果你想使用一个标准的”古怪”的hash函数,比如HMAC,是可以的。但是如果你的目的是想减慢hash的计算速度,那么可以读一下后面讨论的慢速hash函数部分。基于上面讨论的因素,好的做法是使用标准的经过严格测试的hash算法。
hash碰撞(Hash Collisions)
因为hash函数是将任意数量的数据映射成一个固定长度的字符串,所以一定存在不同的输入经过hash之后变成相同的字符串的情况。加密hash函数(Cryptographic hash function)在设计的时候希望使这种碰撞攻击实现起来成本难以置信的高。但时不时的就有密码学家发现快速实现hash碰撞的方法。近的一个例子就是MD5,它的碰撞攻击已经实现了。
碰撞攻击是找到另外一个跟原密码不一样,但是具有相同hash的字符串。但是,即使在相对弱的hash算法,比如MD5,要实现碰撞攻击也需要大量的算力(computing power),所以在实际使用中偶然出现hash碰撞的情况几乎不太可能。一个使用加盐MD5的密码hash在实际使用中跟使用其他算法比如SHA256一样安全。不过如果可以的话,使用更安全的hash函数,比如SHA256, SHA512, RipeMD, WHIRLPOOL等是更好的选择。
正确的方式:如何恰当的进行hash
这部分会详细讨论如何恰当的进行密码hash。第一个章节是基础的,这章节的内容是必须的。后面一个章节是阐述如何继续增强安全性,让hash破解变得异常困难。
基础:使用加盐hash
我们已经知道**黑客可以通过查表和彩虹表的方式快速的获得hash对应的明文密码,我们也知道了通过使用随机的盐可以解决这个问题。但是我们怎么生成盐,怎么在hash的过程中使用盐呢?
盐要使用密码学上可靠安全的伪随机数生成器(Cryptographically Secure Pseudo-Random Number Generator(CSPRNG))来产生。CSPRNG跟普通的伪随机数生成器比如C语言中的rand(),有很大不同。正如它的名字说明的那样,CSPRNG提供一个高标准的随机数,是完全无法预测的。我们不希望我们的盐能够被预测到,所以一定要使用CSPRNG。