跟第三方聯(lián)調(diào)的時(shí)候會(huì)碰到各種加密算法艘策,所以總結(jié)一下刻炒。
1. AES加密
一種對稱加密堤框,要了解三個(gè)概念:密鑰罐寨、填充靡挥、模式
1.1 AES密鑰
- aes密鑰:aes支持三種密鑰長度:128位,192位鸯绿,256位跋破,大家經(jīng)常說的AES128, AES256就是指不同的密鑰長度;
- 不同的密鑰長長度意味著aes加密的輪數(shù)不同瓶蝴,128位加密10輪毒返,192加密12輪,256加密14輪舷手,從安全性角度來講拧簸,256位安全性最高,但是128位因?yàn)榧用茌啍?shù)少聚霜,所以性能更好一些狡恬。
1.2 填充
AES不是將拿到的明文一次性加密珠叔,而是分組加密,就是先將明文切分成長度相等的塊弟劲,每塊大小128bit祷安,再對每一小塊進(jìn)行加密。那么問題就來了兔乞,并不是所有的原始明文串能被等分成128bit汇鞭,例如原串大小200bit,那么第二個(gè)塊只有72bit庸追,所以就需要對第二個(gè)塊進(jìn)行填充處理霍骄,讓第二個(gè)塊的大小達(dá)到128bit。常見的填充模式有
1.2.1 NoPadding:
不進(jìn)行填充淡溯,要求原始加密串大小必須是128bit的整數(shù)倍读整;
1.2.2 PKCS5Padding:
假設(shè)塊大小8字節(jié),如果這個(gè)塊跟8字節(jié)還差n個(gè)字節(jié)咱娶,那么就在原始?jí)K填充n米间,直到滿8字節(jié)。例:塊{1,2,3}膘侮,跟8字節(jié)差了5個(gè)字節(jié)屈糊,那么補(bǔ)全后的結(jié)果{1,2,3,5,5,5,5,5}后面是五個(gè)5,塊{1,2,3,..7}跟8字節(jié)差了1個(gè)字節(jié)琼了,那么補(bǔ)全后就是{1,2,3,...,7,1},就是補(bǔ)了一個(gè)1逻锐。
如果恰好8字節(jié)又選擇了PKCS5Padding填充方式呢?塊{1,2,3...8}填充后變成{1,2,3...8,8...8}雕薪,原串后面被補(bǔ)了8個(gè)8昧诱,這樣做的原因是方便解密,只需要看最后一位就能算出原塊的大小是多少蹦哼。
1.2.3 PKCS7Padding
跟PKCS5Padding的填充方式一樣鳄哭,不同的是,PKCS5Padding只是對8字節(jié)的進(jìn)行填充纲熏,PKCS7Padding可以對1~256字節(jié)大小的block進(jìn)行填充。openssl里aes的默認(rèn)填充方式就是PKCS7Padding
1.3. 模式
AES有多種加密模式锄俄,包括:ECB,CBC,CTR,OCF,CFB,最常見的還是ECB和CBC模式局劲。
1.3.1 ECB模式
最簡單的一種加密模式,每個(gè)塊進(jìn)行獨(dú)立加密奶赠,塊與塊之間加密互不影響鱼填,這樣就能并行,效率高毅戈。
雖然這樣加密很簡單苹丸,但是不安全愤惰,如果兩個(gè)塊的明文一模一樣,那么加密出來的東西也一模一樣赘理。
openssl的相關(guān)函數(shù):
void AES_encrypt (const unsigned char *in, unsigned char *out, const AES_KEY *key)
void AES_decrypt (const unsigned char *in, unsigned char *out, const AES_KEY *key)
1.3.2 CBC模式
CBC模式中引入了一個(gè)新的概念宦言,初始向量iv。iv的作用就是為了防止同樣的明文塊被加密成同樣的內(nèi)容商模。原理是第一個(gè)明文塊跟初始向量做異或后加密奠旺,第二個(gè)塊跟第一個(gè)密文塊做異或再加密,依次類推施流,避免了同樣的塊被加密成同樣的內(nèi)容响疚。
openssl相關(guān)函數(shù):
void AES_cbc_encrypt (const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, const int enc)
int AES_set_decrypt_key (const unsigned char *userKey, const int bits, AES_KEY *key)
敲黑板!瞪醋! 所以跟第三方對接的時(shí)候忿晕,如果對面說他們用aes加密,務(wù)必對他們發(fā)起靈魂三問:
- aes用的什么模式银受?
- aes的填充方式是什么践盼?有的第三方不用標(biāo)準(zhǔn)的填充方式,令人費(fèi)解蚓土,所以一定要問清楚
- 設(shè)置的初始向量是什么宏侍?(如果對方說他們用cbc)
2. RSA
一種非對稱加密方式。需要兩個(gè)密鑰蜀漆,一個(gè)公鑰一個(gè)私鑰谅河,使用其中一把密鑰加密后的明文,只有對應(yīng)的密鑰才能解的開确丢。
rsa可以用來做加密或者做簽名绷耍,兩者性質(zhì)不一樣。
2.1. 簽名和加密的區(qū)別
簽名的作用是讓接受方驗(yàn)證你傳過去的數(shù)據(jù)沒有被篡改鲜侥;加密的作用是保證數(shù)據(jù)不被竊取褂始。
2.2 rsa簽名
原理:你有一個(gè)需要被驗(yàn)簽的原串A。
步驟一:選擇hash算法將A進(jìn)行hash得到hash_a描函;
步驟二:將hash_a進(jìn)行加密崎苗,得到加密值encrypt_a;
步驟三:將原串A和加密的encrypt_a發(fā)給第三方舀寓,第三方進(jìn)行驗(yàn)簽胆数。第三方先解密encrypt_a,得到一個(gè)hash值hash_a1互墓,然后對原串A使用同樣的hash算法進(jìn)行hash必尼,得到的即為加密前的hash_a,如果hash_a = hash_a1, 那么驗(yàn)簽成功。
rsa使用私鑰對信息加密來做簽名,使用公鑰解密去驗(yàn)簽判莉。
openssl相關(guān)函數(shù):
int RSA_sign(int type, const unsigned char *m, unsigned int m_len,
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
int RSA_verify(int type, const unsigned char *m, unsigned int m_len,
unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
注意:兩個(gè)函數(shù)中的m豆挽,是原串hash后的值,type表示生成m的算法券盅,例如NID_sha256表示使用sha256對原串進(jìn)行的hash帮哈,返回1為簽名成功或者驗(yàn)簽成功,-1位為失敗渗饮。
再次敲黑板5! 所以如果第三方說使用rsa驗(yàn)簽互站,要讓對方告知他們的hash算法私蕾。
2.3 rsa加密
首先明確,私鑰加密不等于簽名胡桃。加密的時(shí)候踩叭,使用使用公鑰加密,第三方使用你的私鑰進(jìn)行解密翠胰。
openssl里公鑰加密函數(shù)為RSA_public_encrypt容贝,私鑰解密函數(shù)為RSA_private_decrypt,具體的可以自己去查看下官方文檔之景。
rsa也涉及到了填充方式斤富,所以對接的時(shí)候也要問清楚
在使用公鑰進(jìn)行加密時(shí),會(huì)發(fā)現(xiàn)每次加密出的結(jié)果都不一樣锻狗,但使用私鑰加密時(shí)满力,每次的結(jié)果都一樣,網(wǎng)上查了一圈轻纪,說是因?yàn)樘畛浞绞降脑颉?/p>
官方文檔說明:
EB = 00 || BT || PS || 00 || D .
BT:塊類型
PS:填充字串
D:原始數(shù)據(jù)
BT為00或01或02油额,使用私鑰時(shí)為00和01,這兩種類型下刻帚,PS均為固定值潦嘶;
02類型表示公鑰,這時(shí)PS就變成隨機(jī)的字串崇众,這也就是為什么每次公鑰加密結(jié)果不一樣的原因掂僵。
那么為什么一定要使用私鑰做簽名,公鑰做加密顷歌,而不是公鑰做簽名看峻,私鑰做加密呢?
舉個(gè)栗子:
- A使用公鑰做簽名衙吩,傳輸過程中被劫持,因?yàn)楣€是公開的溪窒,黑客篡改數(shù)據(jù)后使用公鑰重新做簽名坤塞,接受者B用私鑰驗(yàn)簽是可以通過的冯勉;
- A使用私鑰做加密,傳輸過程中被黑客劫持摹芙,因公鑰是公開的灼狰,黑客就能用公鑰解開數(shù)據(jù),拿到原始信息浮禾。