• <option id="cacee"><noscript id="cacee"></noscript></option>
  • <table id="cacee"><noscript id="cacee"></noscript></table>
  • <td id="cacee"></td>
  • <option id="cacee"></option>
  • <table id="cacee"></table>
  • <option id="cacee"><option id="cacee"></option></option>
  • <table id="cacee"><source id="cacee"></source></table><td id="cacee"><rt id="cacee"></rt></td>
    <option id="cacee"><option id="cacee"></option></option>
     找回密碼
     立即注冊

    掃一掃,登錄網站

    首頁 自媒體 查看內容
    • 4652
    • 0
    • 分享到

    區塊鏈的3種加密算法及安全要求詳解(附代碼)

    2018-4-5 14:37

    來源: HiBlock-Net





    歡迎收聽「蝦說區塊鏈」。現在區塊鏈這個概念在互聯網上相當火熱,這里簡單做一個普及,不涉及項目推廣投資,單純地對區塊鏈相關基礎知識概念作一個說明講解。本人區塊鏈技術愛好者,結合相關區塊鏈資料總結整理了「蝦說區塊鏈」,也是自己一個學習筆記,涉及相關內容如理解有誤,也請及時指正。


    1

    SHA-256


    SHA(Secure hash algorithm)安全散列算法,由美國國家安全局(NSA)設計,美國國家標準與技術研究院(NIST)發布的一系列密碼散列函數集,包括了SHA-1、SHA-224、SHA-256、SHA-384、SHA-512等。


    一種哈希函數要達到密碼安全的要求,大致要滿足三個條件:

    碰撞阻力(collision-resistance)、隱秘性(hiding)、謎題友好(puzzle-friendliness)。


    碰撞阻力


    哈希函數作為密碼函數來使用,必須具有良好的碰撞阻力,所謂碰撞阻力即:輸入x、y,x≠y,則H(x)=H(y)不成立。


    事實上哈希函數的碰撞理論上一直存在,根據計數論證和鴿巢原理,簡單想象一下,大量的輸入映射到任意指定的輸出,以無限對待有限,顯而易見,肯定會出現x、y,x≠y,則H(x)=H(y)。


    從工程應用的角度來看,那么一個256位的輸出,選擇2的256次方+1次的輸入,必然出現了碰撞,甚至不需要那么多次的輸出,根據生日悖論理論,輸入2的130次方+1次,得到相同哈希輸出的概率即99.8%。


    根據輸出次數,暫時不論現在熱門的量子計算機,傳統計算機來計算2的128次方的哈希計算,大致需要10的27次方年(假設傳統計算機每秒計算10000次哈希值)。那么這種情況下出現碰撞的概念就認為具有碰撞阻力。


    隱秘性


    同樣也是一個概率問題,H(x)=y,那么根據y無法簡單逆推出x值。


    引入一個信息論中熵(信息熵概念:所有可能性的關系,即每個可能事件發生都有一個概率的問題,熵理解為平均而言發生一個事情信息量的大小,也就是信息量的一個期望)的概念,高階最小熵來描述隨機變量的分散程度。


    還是以256位字符串為例。在計算機中01存儲,那么要獲取x的值,概率在2的256次方分之一,無疑這個概率還是很小的。


    謎題友好


    如果對于任意的n位的輸出值y,y=H(x),無法在較小時間內找到x的值,通過之前的概率的說明,這樣的H哈希函數被認為謎題友好。


    在區塊鏈技術中的SHA-256算法目前認為是一種安全的哈希算法,在2009年中本聰創造區塊鏈技術中選擇了SHA-256算法。


    SHA-256:一種將接受固定長度轉變為接受任意長度輸入的哈希函數,這個稱為MD轉換,也可稱為壓縮函數,所謂壓縮函數就是輸入m長度的值,產生一些長度短一點的n的輸出,輸入可以任意大小,被分為m-n的區塊,然后將每個區塊和之前區塊的輸出一起代入壓縮函數,輸出長度就變成了(m-n)+n=m,對第一個區塊來說,沒有之前的初始向量了,沒有就補一個初始向量,每次調用哈希函數,這些數字就再使用一次,最后一個區塊就是返回結果。SHA-256算法把輸入長度不超過2^64bit,按照512bit分組進行處理,產生一個256bit的報文摘要。

     

    具體步驟:


    • 附加填充比特,對輸入進行填充,使其長度滿足length=448 mod 512,長度為448模512同余,最高位為1,其余位為0,填充范圍在1到512。輸入值后加1,再一直加0,加至長度滿足mod 512=448


    • 附加長度值,將之前原始輸入值的位長度添加在之前的填充結果中。


    • 初始化緩存,使用一個256bit的緩存來存放計算過程中的值和最終結果。該緩存表示為A=0x6A09E667 , B=0xBB67AE85 , C=0x3C6EF372 , D=0xA54FF53A, E=0x510E527F , F=0x9B05688C , G=0x1F83D9AB , H=0x5BE0CD19


    • 處理512bit輸入的分組序列,使用六種邏輯函數迭代運算。由64 步迭代運算組成。每步都以256-bit 緩存值ABCDEFGH 為輸入,然后更新緩存內容。 每步使用一個32-bit 常數值Kt 和一個32-bit Wt。

        

     

    附代碼實現,來自:

    http://blog.csdn.net/c_duoduo/article/details/43889759


    #include

    #include

    #define SHA256_ROTL(a,b) (((a>>(32-b))&(0x7fffffff>>(31-b)))|(a<<b))

    #define SHA256_SR(a,b) ((a>>b)&(0x7fffffff>>(b-1)))

    #define SHA256_Ch(x,y,z) ((x&y)^((~x)&z))

    #define SHA256_Maj(x,y,z) ((x&y)^(x&z)^(y&z))

    #define SHA256_E0(x) (SHA256_ROTL(x,30)^SHA256_ROTL(x,19)^SHA256_ROTL(x,10))

    #define SHA256_E1(x) (SHA256_ROTL(x,26)^SHA256_ROTL(x,21)^SHA256_ROTL(x,7))

    #define SHA256_O0(x) (SHA256_ROTL(x,25)^SHA256_ROTL(x,14)^SHA256_SR(x,3))

    #define SHA256_O1(x) (SHA256_ROTL(x,15)^SHA256_ROTL(x,13)^SHA256_SR(x,10))

    extern char* StrSHA256(const char* str, long long length, char* sha256){

        /*

        計算字符串SHA-256

        參數說明:

        str         字符串指針

        length      字符串長度

        sha256         用于保存SHA-256的字符串指針

        返回值為參數sha256

        */

        char *pp, *ppend;

        long l, i, W[64], T1, T2, A, B, C, D, E, F, G, H, H0, H1, H2, H3, H4, H5, H6, H7;

        H0 = 0x6a09e667, H1 = 0xbb67ae85, H2 = 0x3c6ef372, H3 = 0xa54ff53a;

        H4 = 0x510e527f, H5 = 0x9b05688c, H6 = 0x1f83d9ab, H7 = 0x5be0cd19;

        long K[64] = {

            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,

            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,

            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,

            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,

            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,

            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,

            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,

            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,

        };

        l = length + ((length % 64 >= 56) ? (128 - length % 64) : (64 - length % 64));

        if (!(pp = (char*)malloc((unsigned long)l))) return 0;

        for (i = 0; i < length; pp[i + 3 - 2 * (i % 4)] = str[i], i++);

        for (pp[i + 3 - 2 * (i % 4)] = 128, i++; i < l; pp[i + 3 - 2 * (i % 4)] = 0, i++);

        *((long*)(pp + l - 4)) = length << 3;

        *((long*)(pp + l - 8)) = length >> 29;

        for (ppend = pp + l; pp < ppend; pp += 64){

            for (i = 0; i < 16; W[i] = ((long*)pp)[i], i++);

            for (i = 16; i < 64; W[i] = (SHA256_O1(W[i - 2]) + W[i - 7] + SHA256_O0(W[i - 15]) + W[i - 16]), i++);

            A = H0, B = H1, C = H2, D = H3, E = H4, F = H5, G = H6, H = H7;

            for (i = 0; i < 64; i++){

                T1 = H + SHA256_E1(E) + SHA256_Ch(E, F, G) + K[i] + W[i];

                T2 = SHA256_E0(A) + SHA256_Maj(A, B, C);

                H = G, G = F, F = E, E = D + T1, D = C, C = B, B = A, A = T1 + T2;

            }

            H0 += A, H1 += B, H2 += C, H3 += D, H4 += E, H5 += F, H6 += G, H7 += H;

        }

        free(pp - l);

        sprintf(sha256, "%08X%08X%08X%08X%08X%08X%08X%08X", H0, H1, H2, H3, H4, H5, H6, H7);

        return sha256;

    }

    extern char* FileSHA256(const char* file, char* sha256){

        /*

        計算文件SHA-256

        參數說明:

        file        文件路徑字符串指針

        sha256         用于保存SHA-256的字符串指針

        返回值為參數sha256

        */

        FILE* fh;

        char* addlp, T[64];

        long addlsize, j, W[64], T1, T2, A, B, C, D, E, F, G, H, H0, H1, H2, H3, H4, H5, H6, H7;

        long long length, i, cpys;

        void *pp, *ppend;

        H0 = 0x6a09e667, H1 = 0xbb67ae85, H2 = 0x3c6ef372, H3 = 0xa54ff53a;

        H4 = 0x510e527f, H5 = 0x9b05688c, H6 = 0x1f83d9ab, H7 = 0x5be0cd19;

        long K[64] = {

            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,

            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,

            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,

            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,

            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,

            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,

            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,

            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,

        };

        fh = fopen(file, "rb);

        fseek(fh, 0, SEEK_END);

        length = _ftelli64(fh);

        addlsize = (56 - length % 64 > 0) ? (64) : (128);

        if (!(addlp = (char*)malloc(addlsize))) return 0;

        cpys = ((length - (56 - length % 64)) > 0) ? (length - length % 64) : (0);

        j = (long)(length - cpys);

        if (!(pp = (char*)malloc(j))) return 0;

        fseek(fh, -j, SEEK_END);

        fread(pp, 1, j, fh);

        for (i = 0; i < j; addlp[i + 3 - 2 * (i % 4)] = ((char*)pp)[i], i++);

        free(pp);

        for (addlp[i + 3 - 2 * (i % 4)] = 128, i++; i < addlsize; addlp[i + 3 - 2 * (i % 4)] = 0, i++);

        *((long*)(addlp + addlsize - 4)) = length << 3;

        *((long*)(addlp + addlsize - 8)) = length >> 29;

        for (rewind(fh); 64 == fread(W, 1, 64, fh);){

            for (i = 0; i < 64; T[i + 3 - 2 * (i % 4)] = ((char*)W)[i], i++);

            for (i = 0; i < 16; W[i] = ((long*)T)[i], i++);

            for (i = 16; i < 64; W[i] = (SHA256_O1(W[i - 2]) + W[i - 7] + SHA256_O0(W[i - 15]) + W[i - 16]), i++);

            A = H0, B = H1, C = H2, D = H3, E = H4, F = H5, G = H6, H = H7;

            for (i = 0; i < 64; i++){

                T1 = H + SHA256_E1(E) + SHA256_Ch(E, F, G) + K[i] + W[i];

                T2 = SHA256_E0(A) + SHA256_Maj(A, B, C);

                H = G, G = F, F = E, E = D + T1, D = C, C = B, B = A, A = T1 + T2;

            }

            H0 += A, H1 += B, H2 += C, H3 += D, H4 += E, H5 += F, H6 += G, H7 += H;

        }

        for (pp = addlp, ppend = addlp + addlsize; pp < ppend; pp = (long*)pp + 16){

            for (i = 0; i < 16; W[i] = ((long*)pp)[i], i++);

            for (i = 16; i < 64; W[i] = (SHA256_O1(W[i - 2]) + W[i - 7] + SHA256_O0(W[i - 15]) + W[i - 16]), i++);

            A = H0, B = H1, C = H2, D = H3, E = H4, F = H5, G = H6, H = H7;

            for (i = 0; i < 64; i++){

                T1 = H + SHA256_E1(E) + SHA256_Ch(E, F, G) + K[i] + W[i];

                T2 = SHA256_E0(A) + SHA256_Maj(A, B, C);

                H = G, G = F, F = E, E = D + T1, D = C, C = B, B = A, A = T1 + T2;

            }

            H0 += A, H1 += B, H2 += C, H3 += D, H4 += E, H5 += F, H6 += G, H7 += H;

        }

        free(addlp); fclose(fh);

        sprintf(sha256, "%08X%08X%08X%08X%08X%08X%08X%08X", H0, H1, H2, H3, H4, H5, H6, H7);

        return sha256;

    }


    2

    RIPEMD160


    RIPEMD(RACE Integrity Primitives Evaluation Message Digest),中文譯為“RACE原始完整性校驗消息摘要”,是比利時魯汶大學COSIC研究小組開發的散列函數算法。1996年首次發布RIPEMD-128版本,160位版本RIPEMD-160是對RIPEMD-128的改進,并且是RIPEMD家族中最常見的版本。


    RIPEMD家族中共有四種算法:RIPEMD-128、RIPEMD-160、RIPEMD-256、RIPEMD-320。


    RIPEMD-160采用輸出160位的哈希值,160位的緩存區來存放中間計算過程和最終輸出的值,由5個32位寄存器來構成,核心處理通過10個循環的壓縮函數,每個循環需要16個處理步驟。


    區塊鏈入門時候最難理解的應該就時候這個橢圓加密算法,橢圓加密算法用于生成公鑰生成,現在國密SM2算法的也是基于橢圓機密算法的非對稱算法,這里對橢圓加密算法做個最簡單的介紹。


    參考:

    http://www.pediy.com/kssd/pediy06/pediy6014.htm


    橢圓加密算法是一種公鑰加密體制,最初由Koblitz和Miller兩人于1985年提出,其數學基礎是利用橢圓曲線上的有理點構成Abel加法群上橢圓離散對數的計算困難性。


    有理點:一個n維空間中的幾何物體,它的每一點的坐標可以用(x_1,x_2,...,x_n)表示。如果所有x_i都是有理數,則稱該點為有理點。


    平行線和射影平面:初中數學中有個定理,兩條平行線永不相交。那么這里我們換一種思考方式,兩條平行線在無窮遠處會相交,有一個交點。


    (不要和之前學的數學去較真)然后根據這個理解,出來下面幾個無窮遠處點的性質:


    • 一條直線,無窮遠處點就一個。(一條線你還能要求它有幾個點)

    • 在平面上一組互相平行的平行線在無窮遠處有公共的無窮遠處點。

    • 平面上相交的兩條線在無窮遠處有不同的無窮遠處點。

    • 平面上所有無窮遠處點構成一條直線,叫無窮遠處直線,那平面上的無窮遠處點和正常點構成一個射影平面。


    引入一個射影平面坐標系,聯系下之前初中數學學的平面直角坐標系:


     

     

    那么把坐標系的任意點(x,y),改變成x=X/Z ,y=Y/Z(Z≠0)則坐標系內點可以表示為(X:Y:Z)。有三個參量的坐標就建立了新的坐標體系。例:平面(4,8),射影平面坐標(4Z,8Z,Z),那么Z不等于0,(4,8,1)(8,16,2)(6,12,1.5)這些都是(4,8)在射影平面坐標下的點。再根據初中的坐標直線方程求解,aX+bY+c1Z =0; aX+bY+c2Z =0  (c1≠c2),方程聯立求解,c2Z= c1Z= -(aX+bY)且c1≠c2,aX+bY=0,那么解得(X,Y,0)來表示無窮遠點。那么表示這類型的坐標體系為射影平面坐標系。


    根據上述的方程式,在射影平面坐標系中的橢圓曲線的定義:


     

    該方程名為維爾維斯特拉斯方程,橢圓曲線的形狀不是橢圓,只是因為其描述的方程類似于計算一個橢圓周長的方程。到這里才明白這個名字的來歷。


    加法法則 :任意取橢圓曲線上兩點P、Q (若P、Q兩點重合,則做P點的切線)做直線交于橢圓曲線的另一點R’,過R’做y軸的平行線交于R。我們規定P+Q=R。


     

    曲線上三個點A,B,C處于一條直線上,則A+B+C=O∞  下面,我們利用P、Q點的坐標(x1,y1),(x2,y2),求出R=P+Q的坐標(x4,y4)。 P,Q,R'共線,設為y=kx+b, 若P≠Q,k=(y1-y2)/(x1-x2) 若P=Q,k=(3x2+2a2x+a4 -a1y) /(2y+a1x+a3)  解方程組得到:  x4=k2+ka1-a2-x1-x2;   y4=k(x1-x4)-y1-a1x4-a3;


    到這里說橢圓曲線在密碼學中的應用,其實之前把整個函數理解成一個曲線光滑的連續曲線,結合筆者之前文章講加密中質數分解的說明,加密必須是離散的,那么把橢圓曲線定義在一個有限域上。


    給出一個有限域Fp,這個域只有有限個元素。


    Fp中只有p(p為素數)個元素0,1,2 …… p-2,p-1;

    Fp 的加法(a+b)法則是 a+b≡c (mod p);即,(a+c)÷p的余數 和c÷p的余數相同。

    Fp 的乘法(a×b)法則是  a×b≡c (mod p);

    Fp 的除法(a÷b)法則是  a/b≡c (mod p);即 a×b-1≡c  (mod p);(b-1也是一個0到p-1之間的整數,但滿足b×b-1≡1 (mod p);)。

    Fp 的單位元是1,零元是 0。


    同時,并不是所有的橢圓曲線都適合加密。y2=x3+ax+b是一類可以用來加密的橢圓曲線,也是最為簡單的一類。下面我們就把y2=x3+ax+b 這條曲線定義在Fp上:


    選擇兩個滿足下列條件的小于p(p為素數)的非負整數a、b

          4a3+27b2≠0 (mod p)


    則滿足下列方程的所有點(x,y),再加上 無窮遠點O∞ ,構成一條橢圓曲線。

         y2=x3+ax+b  (mod p)


    其中 x,y屬于0到p-1間的整數,并將這條橢圓曲線記為Ep(a,b)。


    我們看一下y2=x3+x+1  (mod 23)的圖像


     

    橢圓曲線這里成為了離散的點。


    接下來就是加密解密:


    定義個等式:K=kG  [其中 K,G為Ep(a,b)上的點,k為小于n(n是點G的階)的整數]


    根據加法法則,計算K很容易;但給定K和G,求k就相對困難了。 我們把點G稱為基點(base point),k(k<n,n為基點G的階)稱為私有密鑰(privte key),K稱為公開密鑰(public key)。


    整個加密通信過程:

    • 用戶A選定一條橢圓曲線Ep(a,b),并取橢圓曲線上一點,作為基點G。

    • 用戶A選擇一個私有密鑰k,并生成公開密鑰K=kG。

    • 用戶A將Ep(a,b)和點K,G傳給用戶B。

    • 用戶B接到信息后 ,將待傳輸的明文編碼到Ep(a,b)上一點M(編碼方法很多,這里不作討論),并產生一個隨機整數r(r<n)。

    • 用戶B計算點C1=M+rK;C2=rG。

    • 用戶B將C1、C2傳給用戶A。

    • 用戶A接到信息后,計算C1-kC2,結果就是點M。


    因為C1-kC2=M+rK-k(rG)=M+rK-r(kG)=M 再對點M進行解碼就可以得到明文。


    最后說下橢圓曲線優點:與經典的RSA,DSA等公鑰密碼體制相比安全性高,160位的橢圓密鑰與1024位的RSA密鑰安全性相同。處理速度快。在私鑰的加密解密速度上,ecc算法比RSA、DSA速度更快。存儲空間占用小。帶寬要求低。


    3

    SM2國密算法


    SM2國密算法是非對稱密碼算法,基于橢圓加密算法。在目前國內商用密碼中用來替換RSA算法。


    上文中橢圓曲線方程中:y2=x3+ax+b,在SM2算法通過制定公式中a,b的系統,確定唯一標準曲線。同時為了讓曲線映射為加密算法,也確定其他參數,為算法程序使用。SM2算法一般做為簽名、密鑰交換、加密應用。


    算法標準過程:

    • 簽名、驗簽計算過程。

    • 加密、解密計算過程。

    • 密鑰協商計算過程。


    在計算速度來說,SM2簽名速度快、驗簽速度較慢。在簽名原始數據無限制,簽名結果為64字節。


    SM2代碼可參考:

    http://download.csdn.net/download/goldboar/3833072

    參考:http://www.docin.com/p-682659780.html

    版權申明:本內容來自于互聯網,屬第三方匯集推薦平臺。本文的版權歸原作者所有,文章言論不代表鏈門戶的觀點,鏈門戶不承擔任何法律責任。如有侵權請聯系QQ:3341927519進行反饋。
    相關新聞
    發表評論

    請先 注冊/登錄 后參與評論

      回頂部
    • <option id="cacee"><noscript id="cacee"></noscript></option>
    • <table id="cacee"><noscript id="cacee"></noscript></table>
    • <td id="cacee"></td>
    • <option id="cacee"></option>
    • <table id="cacee"></table>
    • <option id="cacee"><option id="cacee"></option></option>
    • <table id="cacee"><source id="cacee"></source></table><td id="cacee"><rt id="cacee"></rt></td>
      <option id="cacee"><option id="cacee"></option></option>
      妖精视频