『壹』 sha1 的hmac演算法c++的 今晚急求!!!!!
HMACSHA1.h文件
#ifndef _IPSEC_SHA1_H_
#define _IPSEC_SHA1_H_
typedef unsigned long__u32;
typedef char__u8;
typedef struct
{
__u32 state[5];
__u32 count[2];
__u8 buffer[64];
} SHA1_CTX;
#if defined(rol)
#undef rol
#endif
#define SHA1HANDSOFF
#define __LITTLE_ENDIAN
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding ring the round function from SSLeay */
#ifdef __LITTLE_ENDIAN
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|(rol(block->l[i],8)&0x00FF00FF))
#else
#define blk0(i) block->l[i]
#endif
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(__u32 state[5], __u8 buffer[64]);
void SHA1Init(SHA1_CTX *context);
void SHA1Update(SHA1_CTX *context, char *data, __u32 len);
void SHA1Final( char digest[20], SHA1_CTX *context);
//void hmac_sha1(unsigned char *to_mac,unsigned int to_mac_length, unsigned char *key,unsigned int key_length, unsigned char *out_mac);
void SHA1_Encode
(
char* k, /* secret key */
int lk, /* length of the key in bytes */
char* d, /* data */
int ld, /* length of data in bytes */
char* out, /* output buffer, at least "t" bytes */
int t
);
#endif /* _IPSEC_SHA1_H_ */
HMACSHA1.cpp 文件
#include"stdafx.h"
#include "HMACSHA1.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#ifndef SHA_DIGESTSIZE
#define SHA_DIGESTSIZE 20
#endif
#ifndef SHA_BLOCKSIZE
#define SHA_BLOCKSIZE 64
#endif
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(__u32 state[5], __u8 buffer[64])
{
__u32 a, b, c, d, e;
typedef union {
unsigned char c[64];
__u32 l[16];
} CHAR64LONG16;
CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
static unsigned char workspace[64];
block = (CHAR64LONG16*)workspace;
// NdisMoveMemory(block, buffer, 64);
memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
}
/* SHA1Init - Initialize new context */
void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void SHA1Update(SHA1_CTX* context, char* data, __u32 len)
{
__u32 i, j;
j = context->count[0];
if ((context->count[0] += len << 3) < j)
context->count[1]++;
context->count[1] += (len>>29);
j = (j >> 3) & 63;
if ((j + len) > 63) {
// NdisMoveMemory(&context->buffer[j], data, (i = 64-j));
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
// NdisMoveMemory(&context->buffer[j], &data[i], len - i);
memcpy(&context->buffer[j], &data[i], len - i);
}
/* Add padding and return the message digest. */
void SHA1Final( char digest[20], SHA1_CTX* context)
{
__u32 i, j; char finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] = ( char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
SHA1Update(context, ( char *)"\200", 1);
while ((context->count[0] & 504) != 448) {
SHA1Update(context, ( char *)"\0", 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = ( char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
i = j = 0;
// NdisZeroMemory(context->buffer, 64);
// NdisZeroMemory(context->state, 20);
// NdisZeroMemory(context->count, 8);
// NdisZeroMemory(&finalcount, 8);
memset(context->buffer, 0x00, 64);
memset(context->state, 0x00, 20);
memset(context->count, 0x00, 8);
memset(&finalcount, 0x00, 8);
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
SHA1Transform(context->state, context->buffer);
#endif
}
void truncate
(
char* d1, /* data to be truncated */
char* d2, /* truncated data */
int len /* length in bytes to keep */
)
{
int i ;
for (i = 0 ; i < len ; i++) d2[i] = d1[i];
}
/* Function to compute the digest */
void SHA1_Encode
(
char* k, /* secret key */
int lk, /* length of the key in bytes */
char* d, /* data */
int ld, /* length of data in bytes */
char* out, /* output buffer, at least "t" bytes */
int t
)
{
SHA1_CTX ictx, octx ;
char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE] ;
char key[SHA_DIGESTSIZE] ;
char buf[SHA_BLOCKSIZE] ;
int i ;
if (lk > SHA_BLOCKSIZE) {
SHA1_CTX tctx ;
SHA1Init(&tctx) ;
SHA1Update(&tctx, k, lk) ;
SHA1Final(key, &tctx) ;
k = key ;
lk = SHA_DIGESTSIZE ;
}
/**** Inner Digest ****/
SHA1Init(&ictx) ;
/* Pad the key for inner digest */
for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x36 ;
for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x36 ;
SHA1Update(&ictx, buf, SHA_BLOCKSIZE) ;
SHA1Update(&ictx, d, ld) ;
SHA1Final(isha, &ictx) ;
/**** Outter Digest ****/
SHA1Init(&octx) ;
/* Pad the key for outter digest */
for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x5C ;
for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x5C ;
SHA1Update(&octx, buf, SHA_BLOCKSIZE) ;
SHA1Update(&octx, isha, SHA_DIGESTSIZE) ;
SHA1Final(osha, &octx) ;
/* truncate and print the results */
t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t ;
truncate(osha, out, t) ;
}
//int main()
//{
//char k[1024],d[1024],out[1024];
//int lk,ld,t;
//strcpy(d,"what do ya want for nothing?");
//strcpy(k,"Jefe");
//lk=strlen(k);
//ld=strlen(d);
//printf("lk=%d\n",lk);
//printf("ld=%d\n",ld);
//t=20;
//hmac_sha(k,lk,d,ld,out,t);
//
//return 0;
//}
調用方法:
SHA_RESULTSIZE =20;
char paramSrc[1024]="aaa";
char keySrc[100]="bbbb";
char sha1Str[SHA_RESULTSIZE] = "";
SHA1_Encode(keySrc,strlen(keySrc),paramSrc,strlen(paramSrc),sha1Str,sizeof(sha1Str));
sha1Str就是最終的值。
『貳』 求祖沖之(zuc)密碼演算法演算法加密C語言實現代碼。
這么久沒人答,我都弄懂了。祖沖之演算法分3個演算法ZUC是祖沖之演算法的核心,僅產生密鍵流KS。供EEA3和EIA3調用。EEA3是加密演算法,用KS捆綁上用戶的密鑰,加密用戶數據D,變成密文。相當於國際上的RSA、DES、AES演算法。作用是對稱的加密解密演算法EIA3是數據完整性演算法,MAC的一種。捆綁上用戶的密鑰,結合KS,生成散列值。相當於國際上的HMAC結合MD5,SHA1的用法。用於密碼授權值的生成和保存。
『叄』 C語言:程序出現錯誤「storage size of 'xx' isn't known 」怎麼辦
1,手頭沒有unix 機器。如果包含了 io.h 還找不到,可以自己用 typedef 定義一個。
2,結構內容可能有:struct _finddata_t{unsigned attrib;time_t time_create;time_t time_access;time_t time_write;_fsize_t size;char name[_MAX_FNAME]}。
3,gcc test.c按照默認進行編譯,無錯誤。
5,在#include <signal.h>之後顯式添加sigaction的頭文件,#include <bits/sigaction.h> 1
6,這樣編譯器會顯式的編譯sigaction的定義,但是這種情況下需要注意,#include<bits/sigaction.h>必須在#include <signal.h>之後,因為signal中會通過#error進行預處理,檢查`bits/sigaction.h是否包含, 如果用戶沒有包含的話,預處理階段就會報錯。
7,你根據程序里用到的它的成員名字,自己假設和定義就可以了。
『肆』 SSL/TLS協議原理解讀
HTTPS是什麼相信大家都知道,如果你不知道。。。請關閉此文!!!
HTTP的數據是明文傳輸的,沒有安全性可言。HTTPS是秘文傳輸,那麼HTTPS是怎麼實現數據的安全(加密)傳輸的?那是因為HTTPS比HTTP多了個'S'。 即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。
SSL/TLS協議是網路安全通信的重要基石,本文將簡單介紹SSL/TLS協議,主要關注SSL/TLS協議的安全性,特別是SSL規范的正確實現。 本系列的文章大體分為幾個部分:
1、SSL/TLS簡介
2、SSL/TLS協議的基本流程
3、從SSL到TLS
4、SSL/TLS的流行實現庫
SSL全稱是Secure Sockets Layer,安全套接字層,它是由網景公司(Netscape)設計的主要用於Web的安全傳輸協議,目的是為網路通信提供機密性、認證性及數據完整性保障。如今,SSL已經成為互聯網保密通信的工業標准。
SSL最初的幾個版本(SSL 1.0、SSL2.0、SSL 3.0)由網景公司設計和維護,從3.1版本開始,SSL協議由網際網路工程任務小組(IETF)正式接管,並更名為TLS(Transport Layer Security),發展至今已有TLS 1.0、TLS1.1、TLS1.2這幾個版本。
如TLS名字所說,SSL/TLS協議僅保障傳輸層安全。同時,由於協議自身特性(數字證書機制),SSL/TLS不能被用於保護多跳(multi-hop)端到端通信,而只能保護點到點通信。
SSL/TLS協議能夠提供的安全目標主要包括如下幾個:
認證性——藉助數字證書認證伺服器端和客戶端身份,防止身份偽造
機密性——藉助加密防止第三方竊聽
完整性——藉助消息認證碼(MAC)保障數據完整性,防止消息篡改
重放保護——通過使用隱式序列號防止重放攻擊
為了實現這些安全目標,SSL/TLS協議被設計為一個兩階段協議,分為握手階段和應用階段:
握手階段也稱協商階段,在這一階段,客戶端和伺服器端會認證對方身份(依賴於PKI體系,利用數字證書進行身份認證),並協商通信中使用的安全參數、密碼套件以及MasterSecret。後續通信使用的所有密鑰都是通過MasterSecret生成。
在握手階段完成後,進入應用階段。在應用階段通信雙方使用握手階段協商好的密鑰進行安全通信。
Handshake協議:包括協商安全參數和密碼套件、伺服器身份認證(客戶端身份認證可選)、密鑰交換;
ChangeCipherSpec 協議:一條消息表明握手協議已經完成;
Alert 協議:對握手協議中一些異常的錯誤提醒,分為fatal和warning兩個級別,fatal類型的錯誤會直接中斷SSL鏈接,而warning級別的錯誤SSL鏈接仍可繼續,只是會給出錯誤警告;
Record 協議:包括對消息的分段、壓縮、消息認證和完整性保護、加密等。
圖2、圖3都是表示的協議流程,大同小異。可以對比著看加深理解。
每一個SSL/TLS鏈接都是從握手開始的,握手過程包含一個消息序列,用以協商安全參數、密碼套件,進行身份認證以及密鑰交換。握手過程中的消息必須嚴格按照預先定義的順序發生,否則就會帶來潛在的安全威脅。今年頂級安全會議CCS 有文章提出了建立綜合狀態機來檢查SSL鏈接中消息序列……
2.1 握手過程中的消息序列
ClientHello:ClientHello通常是握手過程中的第一條消息,用於告知伺服器客戶端所支持的密碼套件種類、最高SSL/TLS協議版本以及壓縮演算法。
ClientHello中還包含一個隨機數,這個隨機數由4個位元組的當前GMT UNIX時間以及28個隨機選擇的位元組組成,共32位元組。該隨機數會在密鑰生成過程中被使用。
另外,ClientHello中還可能包含客戶端支持的TLS擴展。(TLS擴展可以被用來豐富TLS協議的功能或者增強協議的安全性)
ServerHello:伺服器接受到ClientHello後,會返回ServerHello。伺服器從客戶端在ClientHello中提供的密碼套件、SSL/TLS版本、壓縮演算法列表裡選擇它所支持的項,並把它的選擇包含在ServerHello中告知客戶端。接下來SSL協議的建立就基於伺服器選擇的密碼套件類型、SSL/TLS協議版本以及壓縮演算法。
ServerHello中同樣會包含一個隨機數,同樣4+28 位元組類型,由伺服器生成。
Certificate:客戶端和伺服器都可以發送證書消息來證明自己的身份,但是通常客戶端證書不被使用。 伺服器一般在ServerHello後會接一條Certificate消息,Certificate消息中會包含一條證書鏈,從伺服器證書開始,到Certificate authority(CA)或者最新的自簽名證書結束。下圖形象地描述了證書鏈:
SSL中使用的證書通常是X.509類型證書,X.509證書的內容如下表所示:
在用的X.509證書包含Version 1和Version 3兩種版本,其中v1版本的證書存在安全隱患,同時不支持TLS擴展,被逐漸棄用。現在大多數在用的SSL證書都是V3版本。
同時證書會附帶與協商好的密鑰交換演算法對應的密鑰。密鑰交換演算法以及它們所要求的密鑰類型如下表所示。
ServerKeyExchange:該消息僅當以下密鑰交換演算法被使用時由伺服器發出:
RSA_EXPORT(僅當伺服器的公鑰大於512bit時)、DHE_DSS、DHE_DSS_EXPORT、DHE_RSA、DHE_RSA_EXPORT、DH_anon 使用其它密鑰交換演算法時,伺服器不能發送此消息。
ServerkeyExchange消息會攜帶這些密鑰交換演算法所需要的額外參數,以在後續步驟中協商PreMasterSecret。這些參數需要被簽過名。
CertificateRequest:這個消息通常在要求認證客戶端身份時才會有。消息中包含了證書類型以及可接受的CA列表。
ServerHelloDone:伺服器發送這條消息表明伺服器部分的密鑰交換信息已經發送完了,等待客戶端的消息以繼續接下來的步驟。這條消息只用作提醒,不包含數據域。
ClientKeyExchange:這條消息包含的數據與所選用的密鑰交換演算法有關。
如果選擇的密鑰交換演算法是RSA,那麼消息包含的參數為用伺服器RSA公鑰(包含在之前證書中的或者是ServerKeyExchange中的)加密過的PreMasterSecret,它有48個位元組,前2個位元組表示客戶端支持的最高協議版本,後46個位元組是隨機選擇的。
如果選擇的密鑰交換演算法是DH或者DHE,則可能有兩種情況:
隱式DH公開值:包含在Certificate消息里;
顯示DH公開值:公開值是本消息的一部分。
CertificateVerify:這條消息用來證明客戶端擁有之前提交的客戶端證書的私鑰。
Finished:表明握手階段結束。這是第一條用協商的演算法和密鑰保護的消息。
因為是用協商好的密鑰加密的消息,它可以用來確認已經協商好的密鑰。
同時Finished消息包含一個verify_data域,可以用來校驗之前發送和接收的信息。
Verify_data域是一個PRF函數的輸出(pseudo-random function)。這個偽隨機函數的輸入為:(1)兩個hash值:一個SHA-1,一個MD5,對之前握手過程中交換的所有消息做哈希;(2)the MasterSecret,由預備主密鑰生成;(3)finished_label,如果客戶端發送的則是」client finished」,伺服器發送的則是」server finished」。關於這個PRF的細節在3.3節中會具體描述。 此外,Finished 消息不能夠在ChangeCipherSpec前發送。
2.2 不同密鑰交換演算法對應的握手過程
不同的密鑰交換演算法對應的握手過程中的消息序列是不同的,相應的實現方式也不同,本節介紹幾個常見密鑰交換演算法對應的握手過程。
TLS-RSA:在這個場景下,PreMasterSecret是由客戶端指定的,並用RSA公鑰加密發送給伺服器。伺服器不影響PReMasterSecret的生成。
TLS-DH:基於DH的密鑰交換也被稱為靜態Diffie-Hellman。在這種場景下,可能是雙方各自提交一個證書包含DH公開值,或者伺服器端提交證書包含DH公開值,客戶端在每次會話中選擇一個值。協商好的DH值被用作PreMasterSecret。顯然證書中的參數是固定的,那麼每次鏈接的PreMasterSecret也是相同的。
TLS-DH不能提供前向安全性。
TLS-DHE:基於DHE的TLS握手中會有ServerKeyExchange消息。握手過程中交換參數的認證通過數字簽名來實現,支持的簽名演算法包括RSA和DSS。DH參數會有它的數字簽名一起被包含在ServerKeyExchange中被發送出去。客戶端在ClientKeyExchange中返回它的公開DH參數,但沒有簽名保護。同樣協商出來的DH密鑰被用作PreMasterSecret。
2.3 密鑰生成
Pseudo-random Function(PRF):偽隨機函數是SSL協議中的一個重要組成部分,它被用來秘密擴展以及生成密鑰。在3.1節講解Finished消息時已經簡單提及PRF,在這里我們詳細討論PRF的工作原理。SSL/TLS協議中的PRF如下圖所示:
這個PRF基於兩個hash函數:MD5和SHA-1,它有3個輸入,一個Secret(比如PreMasterSecret),一個標志符(比如」client finished」, 「server finished」),還有一個種子值(比如客戶端隨機數+伺服器端隨機數)。
Secret在使用時被分為長度相同的兩半:S1和S2,分別作為P_MD5和P_SHA-1的輸入。
PRF的輸出按如下方式處理得到:
P_MD5和P_SHA-1都是擴展函數,用來擴展秘密值以用於密鑰生成,它們的計算方式如下:
其中A(0) = seed, A(i) = HMAC hash( secret, A( i −1) )
這個秘密擴展會一直進行直到得到足夠多的擴展數據。 Key Derivation:主密鑰(MasterSecret)是利用上述PRF從預備主密鑰(PreMasterSecret)生成的。每個MasterSecret為48位元組,生成方式如下:
得到MasterSecret後,它會被進一步處理最後生成4個不同的密鑰和2個初始向量(IV)。處理過程如下:
處理過程一直持續到足夠多的輸出被生成,然後把輸出分為4個key和2個IV:
下圖完整闡述了SSL/TLS協議中的密鑰生成過程。
本節介紹SSL/TLS協議的版本變遷,不同版本的區別以及安全特性等。
SSL 1.0由於從來沒有被公開過,並且存在嚴重安全漏洞,我們就不討論了。
SSL 2.0:SSL 2.0於1995年4月被發布。SSL 2.0中主要存在的問題如下:
MAC不能覆蓋填充長度域,攻擊者可能利用這點破壞消息完整性;
缺乏握手認證,攻擊者可以篡改密碼套件列表,誘騙通信雙方使用較弱的密碼套件;
使用較弱的或有問題的密碼演算法(如MD5,RC4等),或者使用不安全的分組模式(如CBC模式);
對於不同的密碼學基元使用相同的密鑰,違背基本安全常識。
由於以上安全問題,RFC 6176已經明確提出避免使用SSL 2.0,但是現實生活中還有少量客戶端和伺服器支持SSL 2.0.
SSL 3.0:SSL 3.0引入了一些新的特性和機制解決了很多之前版本存在的漏洞。此外,SSL 3.0中引入了ChangeCipherSpec子協議。SSL 3.0向後兼容SSL 2.0,相對於SSL 2.0,它的主要改變包括以下幾點:
支持更多的密碼套件(支持更多的密碼演算法如DSS,SHA-1)
在握手階段支持密鑰協商(DH和FORTEZZA)
支持密碼學參數的重協商
增加了消息壓縮選項
MAC能夠覆蓋填充長度域了,同時MAC可以使用MD5或者SHA-1
不同的密碼學基元使用不同的key
Alert子協議能對任何錯誤給出兩種提示:Warning和Fatal
中止鏈接的時候會用一個close_notify警告通知通信雙方
支持證書鏈,而非單個證書
通過Finished消息認證所有發送和接收的消息
加密了的PreMasterSecret包含當前使用的協議版本,防止協議回滾
TLS 1.0:TLS 1.0和SSL 3.0差別非常小。實際上,TLS 1.0是SSL 3.1,在IETF接手後改名為TLS。TLS 1.0版本是目前使用最廣泛的SSL/TLS協議版本。
TLS 1.0不再支持使用FORTEZZA的密碼套件。
TLS 1.0中MAC被替換成HMAC。
之前提到ChangeCipherSpec消息必須在Finished消息前發送,在TLS 1.0中,如果消息序列不符合這個要求,會產生FATAL警告並終止鏈接。
TLS 1.1:這個版本相比之前改動也很小。最重要的改動是預防了針對CBC分組模式的一些攻擊。現在的填充錯誤變的和非法MAC錯誤不可區分了,防止攻擊者利用可區分錯誤響應建立解密預言機對密文進行攻擊。
在每次加密過程中,使用CBC分組模式時,都需要顯示給出IV,而不用再密鑰生成時使用PRF生成IV。
此外,TLS 1.1禁止為適應之前出口限制而使用弱化的密碼套件。
TLS 1.2:這是最新的版本,部署的還比較少。這個版本禁用了PRF中的MD5和SHA-1,而用一個可配置的hash函數取代了它們,這樣的修改簡化了計算過程。修改後的PRF風格如下:
此外,TLS 1.2的一個重要變化是支持認證加密模式(支持GCM等)。但是由於一些AEAD(Authenticated Encryption with Associated Data)密碼演算法要求IV為隱式的,所以IV又恢復到由MasterSecret生成,即TLS 1.0以前的風格。
TLS 1.2支持使用GCM、CCM的新密碼套件。
同時SSL 2.0被宣布放棄,不再向後兼容SSL 2.0.
本節簡單介紹一下流行的SSL/TLS實現庫,SSL協議非常復雜,由開發者自己實現常常會出錯,開發者在具體實現SSL協議時通常會依賴於這些密碼學庫。
4.1 常見的SSL/TLS 實現
OpenSSL:這是非常流行的開源SSL/TLS實現。
OpenSSLim完全用C語言實現,支持SSL 2.0/3.0,TLS 1.0/1.1/1.2以及DTLS 1.0。
OpenSSL 近年來出現了很多的安全漏洞,比如2014年曝出的著名的Heartbleed漏洞等。
JSSE:這是使用Java實現的,支持SSL 3.0,TLS 1.0/1.1/1.2.
Bouncy Castle:它不僅僅支持SSL/TLS,它是一個完整的密碼學庫,支持各種密碼學演算法和協議。不過它僅僅支持TLS 1.0版本。
Android平台主要使用這個密碼學庫。
GnuTLS:這是另一個用C語言實現的庫,支持SSL 3.0,TLS 1.0/1.1/1.2以及DTLS 1.0。主要在Unix世界被使用。同時以各種安全漏洞多而聞名。
NSS:這是最初由網景公司(Netscape)開發的庫,支持SSL 2.0/3.0,TLS 1.0/1.1,現在主要被瀏覽器和客戶端軟體使用,比如Firefox使用的就是NSS庫,Chrome使用的是一個NSS庫的修正版。
下表是一些常見軟體以及它們所使用的SSL/TLS實現庫的情況:
其它還有一些常用的SSL實現庫,如cryptlib、CyaSSL、MatrixSSL、PolarSSL等,由於市場佔有率不高,我們這里就不多做介紹了。
4.2 流行SSL/TLS實現庫的安全研究
最近幾年曝出的高風險SSL安全漏洞大多跟SSL實現庫有關,比如2014年4月曝出的「心臟滴血」漏洞,存在於OpenSSL 1.0.1-1.0.1f版本中,影響全球近17%的Web伺服器;同樣是2014年曝出的蘋果公司iOS 7.0.6版本系統中存在的「gotofail」漏洞,因為程序員的疏忽導致SSL證書校驗中的簽名校驗失效;包括今年曝出的SSL Freak攻擊也是由於SSL實現庫的安全漏洞導致的攻擊,我們研究小組的同學對這個攻擊有詳細的分析,參見《SSL Freak來襲:如何實施一個具體的SSL Freak攻擊》。同時我們還開發了一個基於python的中間人代理攻擊框架「風聲」對某國內知名電商的伺服器進行具體的攻擊,並上報了漏洞。
考慮到大量SSL/TLS實現庫中存在安全問題,同時這些主流的SSL/TLS實現庫對開發者而言使用難度較高,比如有些SSL/TLS實現庫要求開發者自己進行隨機數生成或密鑰管理,讓缺乏系統信息安全知識培訓的開發者去使用這樣高度復雜的密碼學庫容易產生很多安全問題。我們在這里推薦一些高級密碼學庫:Google keycazer、NaCl、Cryptlib、GPGME。這些密碼學庫存在的安全問題較少,同時封裝了一些底層的密碼學操作,降低了開發者的使用難度。
以上就是本次要介紹的SSL /TLS協議基本知識,後續的文章我們會對一些典型SSL/TLS攻擊進行具體介紹。
參考:
1、 http://netsecurity.51cto.com/art/201505/476337.htm
2、 http://www.cnblogs.com/NathanYang/p/9183300.html
3、 https://www.cnblogs.com/bhlsheji/p/4586597.html
『伍』 C++或者C可以寫游戲腳本嗎
只能寫小游戲· ···稍微大型的游戲都需要所謂游戲引擎來帶動··腳本編寫改成了游戲所用引擎的代碼!