在Web开发中,编码与解码、签名、加密与解密是非常常见的问题。本文不会介绍具体实例,而是介绍这些的原理、用途与区别。
一、编码与解码
        在Web开发中,需要通过URL的query参数来传递数据,但是对于URL来说,有些字符是不安全的,所以需要对此进行编码。常见的编码方式有Base64,关于Base64的详细信息可以参见这里。但是Base64中有+这种对于URL不安全的字符,这就衍生出了URL安全的Base64编码,简单地说就是基本Base64编码的改进。
        其实 ,也不定要做Base64,也可以直接用URL编码来规避不全字符,关于URL编码与解码的详细信息请参见这里
        对于发送方来说,就是编码,反之,对于接收方来说,就是解码。

二、签名
        签名的场景很多,比如:在云盘中,会对文件进行MD5签名,对于相同文件之存一份来节省空间和做到秒传;在TCP/IP中,会用CRC来对通讯数据做签名,用于校验数据是否被篡改,已决定是否丢弃。
        常见的签名方式有很多,比如:MD5、SHA系列、HmacSHA系列、CRC等。
1、MD5
        MD5即Message-Digest Algorithm 5(信息-摘要算法 5),用于确保信息传输完整一致,是计算机广泛使用的散列算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。 将数据(如汉字)运算为另一固定长度值,是散列算法的基础原理,MD5的前身有MD2、MD3和MD4。
        MD5一度被广泛应用于安全领域,但是由于MD5的弱点被不断发现以及计算机能力不断的提升,现在已经可以构造两个具有相同MD5的信息,使本算法不再适合当前的安全环境。目前,MD5计算广泛应用于错误检查,例如:在一些BitTorrent下载中,软件通过计算MD5和检验下载到的碎片的完整性。
        MD5是输入不定长度信息,输出固定长度128-bits的算法,经过程序流程,生成四个32位数据,最后联合起来成为一个128-bits散列。基本方式为,求余、取余、调整长度、与链接变量进行循环运算,得出结果。
2、SHA系列
        SHA是一个系列,SHA-1在许多安全协议中广为使用,包括TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被视为是MD5(更早之前被广为使用的散列函数)的后继者。但SHA-1的安全性如今被密码学家严重质疑,因此,为了解决问题而衍生出了SHA-224、SHA-256、SHA-384和SHA-512,这些算法并称为SHA-2。
        SHA-2并没有接受像SHA-1一样的公众密码社区做详细的检验,所以它们的密码安全性还不被大家广泛的信任。虽然至今尚未出现对SHA-2有效的攻击,它的算法跟SHA-1基本上仍然相似,因此有些人开始发展其它替代的散列算法。
        SHA-3,之前名为Keccak算法,是一个加密杂凑算法。SHA-3并不是要取代SHA-2,因为SHA-2目前并没有出现明显的弱点。由于对MD5出现成功的破解,以及对SHA-0和SHA-1出现理论上破解的方法,NIST感觉需要一个与之前算法不同的,可替换的加密杂凑算法,也就是现在的SHA-3。
3、HmacSHA系列
        HmacSHA也是一个系列,有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512、HmacMD5等,这里以HmacSHA1为例说明之。
        HmacSHA1是从 SHA1 哈希函数构造的一种键控哈希算法,被用作 HMAC(基于哈希的消息验证代码)。 此 HMAC 进程将密钥与消息数据混合,使用哈希函数对混合结果进行哈希计算,将所得哈希值与该密钥混合,然后再次应用哈希函数。 输出的哈希值长度为160位。HmacSHA1接受任何大小的密钥,并产生长度为160位的哈希序列。
        在发送方和接收方共享机密密钥的前提下,HMAC 可用于确定通过不安全信道发送的消息是否已被篡改。 发送方计算原始数据的哈希值,并将原始数据和哈希值放在一个消息中同时传送。 接收方重新计算所接收消息的哈希值,并检查计算所得的 HMAC 是否与传送的 HMAC 匹配。
        因为更改消息和重新生成正确的哈希值需要密钥,所以对数据或哈希值的任何更改都会导致不匹配。 因此,如果原始的哈希值与计算得出的哈希值相匹配,则消息通过身份验证。
        简单来说就是确认请求的URL或者参数是否存在被篡改,以QQ签名为例:发送方(自己)将参数等进行HMAC算法计算,将得到的哈希值(即签名值)与请求的参数一同提交至接收方(QQ端),然后接收方再次将参数等值进行HMAC算法计算,将得到的哈希值与你传递过来的哈希值进行核对验证,若一样,说明请求正确、验证通过,进行一下步工作,若不一样,将返回错误。 
        这里有两个不错的在线签名工具,请分别参看这里这里,以备平时测试用。

三、加密与解密
        有时候对数据签名并不能满足我们的需求,比如:在移动应用中明文传递imei、idfa或者mac会存在一定的风险;在Web开发中传递密码或者价格有关的信息,这些都需要接收方反解数据,这种场景仅仅签名就不够了。
        加密与解密简单说就是发送方用密钥对数据进行加密,接收方用密钥对数据进行解密来满足上面场景需求。
        常用的加密与解密算法有很多种,比如:DES系列、RC系列、AES(Rijndael)、BlowFish、RSA等。
1、DES系列
        DES即数据加密标准(Data Encryption Standard),由IBM设计作为非机密数据的正式数据加密标准,速度较快,适用于加密大量数据的场合。
        DES算法的入口参数有三个:Key、Data、Mode,其中,Key为8个字节共64位,是DES算法的工作密钥;Data也为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作模式,有两种:加密或解密。
        当模式为加密模式时,明文按照64位进行分组,形成明文组,key用于对数据加密,当模式为解密模式时,key用于对数据解密。实际运用中,密钥只用到了64位中的56位,这样才具有高的安全性。
        3DES即(Triple DES),是DES向AES过度的加密算法,它以DES为基本模块,通过组合分组方法设计出分组加密算法,对一块数据使用三个不同的64位密钥进行三次加密,强度较DES更高。假设Ek()和Dk()代表DES算法的加密和解密过程,K代表DES算法使用的密钥,P代表明文,C代表密表,这样:
        3DES加密过程为:C=Ek3(Dk2(Ek1(P)))
        3DES解密过程为:P=Dk1((EK2(Dk3(C)))
        K1、K2、K3决定了算法的安全性,若三个密钥互不相同,本质上就相当于用一个长为168位的密钥进行加密。多年来,它在对付强力攻击时是比较安全的。若数据对安全性要求不那么高,K1可以等于K3。在这种情况下,密钥的有效长度为112位。
2、RC系列
        RC系列包括RC2、RC4,用变长密码对大量数据进行加密,比DES快。
        RC2可作为DES算法的建议替代算法。它的输入和输出都是64比特。密钥的长度是从1字节到128字节可变,但目前的实现是8字节(1998年)。此算法被设计为可容易地在16位的微处理器上实现。在一个IBM AT机上,RC2加密算法的执行可比DES算法快两倍(假设进行密钥扩展)。
        RC4是密钥长度可变的流加密算法,RC4由伪随机数生成器和异或运算组成,RC4的密钥长度可变,范围是[1,255],但一般为256字节。RC4一个字节一个字节地加解密。给定一个密钥,伪随机数生成器接受密钥并产生一个S-box,S-box用来加密数据,而且在加密过程中S-box会变化。RC4的速度可以达到DES的10倍左右,且具有很高级别的非线性,是有线等效加密(WEP)中采用的加密算法,也是安全套接层(SSL)可采用的算法之一。
3、IDEA
        IDEA即(International Data Encryption Algorithm)国际数据加密算法,在DES基础上发展出来,类似于3DES,使用128位密钥提供非常强的安全性。IDEA设计了一系列加密轮次,每轮加密都使用从完整的加密密钥中生成的一个子密钥,与DES的不同处在于,它采用软件实现和采用硬件实现同样快速。
        由于IDEA是在美国之外提出并发展起来的,避开了美国法律上对加密技术的诸多限制,因此,有关IDEA算法和实现技术的书籍都可以自由出版和交流,可极大地促进IDEA的发展和完善。IDEA曾今也是AES算法标准的主要竞争者,其安全性已经在国际密码年会上被证明。 
3、AES(Rijndael)
        AES即高级加密标准(Advanced Encryption Standard),是下一代的加密算法标准,速度快,安全级别高,目前AES标准的一个实现是Rijndael算法
        AES算法基于排列和置换运算,排列是对数据重新进行安排,置换时将一个数据单元替换为另一个。AES的分组区块长度固定为128比特,密钥长度则可以是128,192或256比特(如果数据块及密钥长度不足时,会补齐)。
        AES加密有很多轮的重复和变换。大致步骤如下:1、密钥扩展(KeyExpansion),2、初始轮(Initial Round),3、重复轮(Rounds),每一轮又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,4、最终轮(Final Round),最终轮没有MixColumns。
        AES加密过程是在一个4×4的字节矩阵上运作,这个矩阵又称为“状态(state)”,其初值就是一个明文区块(矩阵中一个元素大小就是明文区块中的一个Byte)。加密时,各轮AES加密循环(除最后一轮外)均包含以下4个步骤:
        (1)AddRoundKey:矩阵中的每一个字节都与该次轮秘钥(round key)做XOR运算,每个子密钥由密钥生成方案产生(即Rijndael密钥生成方案)。
        (2)SubBytes:通过一个非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。
        (3)ShiftRows:将矩阵中的每个横列进行循环式移位。
        (4)MixColumns:为了充分混合矩阵中各个直行的操作,这个步骤使用线性转换来混合每列的四个字节。
        最后一个加密循环中省略MixColumns步骤,而以另一个AddRoundKey取代。
        关于AES(Rijndael)算法的实现可以参见这里
4、BlowFish
        BlowFish使用变长的密钥,长度可达448位,数据块大小是64bit(8字节),加解密速度很快。
        OpenSSL中提供了BlowFish算法的实现,主要包括三个函数:
        void BF_set_key(BF_KEY *key, int len, const unsigned char *data)
        void BF_encrypt(BF_LONG *data,const BF_KEY *key)
        void BF_decrypt(BF_LONG *data,const BF_KEY *key)
        BF_set_key函数,它是用来初始化密钥的,把密钥信息(首地址是data,长度为len的字节数组)设置到BF_KEY结构里。设置之后,我们只需要使用BF_KEY结构就可以表征密钥了,在后续调用加解密函数时,我们只需要把这个结构传递进去就可以了。这里需要注意的一点是Blowfish实际使用的密钥是根据用户的密钥信息进行运算产生的,这是一个比较耗时的过程,这个BF_set_key函数就进行了密钥初始化的过程,所以,我们应该调用一次BF_set_key,然后重复使用经过初始化后的BF_KEY结构,而不是每次需要加解密时都用data和len来重新初始化一把BF_KEY。
        BF_encrypt和BF_decrypt顾名思义就是用于数据加解密的,输入/输出使用相同参数来传入传出,即参数BF_LONG *data。
        -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
        以上算法都属于对称密钥算法,密钥都是私有的,不公开。所谓对称加密,简单来说,“加密”就是把容易识别的信息变成不易识别的信息;而“对称”则表示加密者和解密者之间拥有相同的密钥。
        对称密钥的缺陷在于其安全性依赖于加密算法的强大和密钥的私密性,而密钥又必须让解密方知道,这对于有些应用场景来说本身就是不安全的,这样就产生了非对称加密。
5、RSA
        非对称加密/解密算法中加密和解密使用不同的密码,有代表性的有RSA、DSA、ElGamal和ECDSA,这里以RSA为例说明之。非对称加密/解密的安全性是基于复杂数学难题,特点是运算复杂、速度慢(极端情况下慢上1000倍),主要应用于金融、军事等重大机密的系统(这些系统中极有可能所有出口都有间谍监听,传递私密密钥是不安全的)。
        非对称加密算法(asymmetric cryptographic algorithm)又名“公开密钥加密算法”,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey),其工作原理如下:
        (1)A要向B发送信息,A和B都要产生一对用于加密和解密的公钥和私钥。  
        (2)A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。
        (3)A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。
        (4)A将这个消息发给B(已经用B的公钥加密消息)。
        (5)B收到这个消息后,B用自己的私钥解密A的消息。其他所有收到这个报文的人都无法解密,因为只有B才有B的私钥。
        RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。RSA密钥长度随着保密级别提高,增加很快,只要其钥匙的长度足够长(RSA密钥长度一般在1024bits及以上,比如:1024、2048、3072、7680等),用RSA加密的信息实际上是不能被解破的。
        RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。
        RSA的算法涉及三个参数,n、e1、e2。
        其中,n是两个大质数p、q的积,n的二进制表示时所占用的位数,就是所谓的密钥长度。
        e1和e2是一对相关的值,e1可以任意取,但要求e1与(p-1)*(q-1)互质;再选择e2,要求(e2*e1)mod((p-1)*(q-1))=1。
        (n,e1),(n,e2)就是密钥对。其中,(n,e1)为公钥,(n,e2)为私钥。
        RSA加解密的算法完全相同,假设A为明文,B为密文,则:A=B^e2 mod n;B=A^e1 mod n;(公钥加密体制中,一般用公钥加密,私钥解密)
        e1和e2可以互换使用,即:
        A=B^e1 mod n;B=A^e2 mod n;
        速度一直是RSA的缺陷,一般来说只用于少量数据加密,RSA的速度比对应同样安全级别的对称密码算法要慢1000倍左右。

posted on 2015-07-06 16:45  露露的博客  阅读(792)  评论(0编辑  收藏  举报