반응형

사실 SHA256이나 MD5 같은 단방향 암호화를 전송하는측에서 왜 해야 하는지 의문이 들기도 하지만,
모든 개발이 생각하는대로 흘러가지 않는만큼 여러가지(?) 이유로 전송하는 문자열을 암호화 해야 하는 이슈가 발생하였다.

암호화를 SHA-256으로 하기로 협업과 약속하고 자바스크립트로 SHA256 암호화 할 수 있는 방법으로 구글링 해 보니, 쉽게 찾을 수 있었다. 이미 외국의 개발자분이 자바스크립트로 구성된 함수를 제작하여 공개하셨다.

함수는 아래와 같으며, 원 출처지인 http://www.webtoolkit.info/javascript_sha256.html#.VuJRJuY4tFC 을 통해서도 확인이 가능하다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<script type="text/javascript">
    /**
    *
    *  Secure Hash Algorithm (SHA256)
    *  http://www.webtoolkit.info/
    *
    *  Original code by Angel Marin, Paul Johnston.
    *
    **/
      
    function SHA256(s){
      
        var chrsz   = 8;
        var hexcase = 0;
      
        function safe_add (x, y) {
            var lsw = (x & 0xFFFF+ (y & 0xFFFF);
            var msw = (x >> 16+ (y >> 16+ (lsw >> 16);
            return (msw << 16| (lsw & 0xFFFF);
        }
      
        function S (X, n) { return ( X >>> n ) | (X << (32 - n)); }
        function R (X, n) { return ( X >>> n ); }
        function Ch(x, y, z) { return ((x & y) ^ ((~x) & z)); }
        function Maj(x, y, z) { return ((x & y) ^ (x & z) ^ (y & z)); }
        function Sigma0256(x) { return (S(x, 2) ^ S(x, 13) ^ S(x, 22)); }
        function Sigma1256(x) { return (S(x, 6) ^ S(x, 11) ^ S(x, 25)); }
        function Gamma0256(x) { return (S(x, 7) ^ S(x, 18) ^ R(x, 3)); }
        function Gamma1256(x) { return (S(x, 17) ^ S(x, 19) ^ R(x, 10)); }
      
        function core_sha256 (m, l) {
             
            var K = new Array(0x428A2F980x713744910xB5C0FBCF0xE9B5DBA50x3956C25B0x59F111F1,
                0x923F82A40xAB1C5ED50xD807AA980x12835B010x243185BE0x550C7DC3,
                0x72BE5D740x80DEB1FE0x9BDC06A70xC19BF1740xE49B69C10xEFBE4786,
                0xFC19DC60x240CA1CC0x2DE92C6F0x4A7484AA0x5CB0A9DC0x76F988DA,
                0x983E51520xA831C66D0xB00327C80xBF597FC70xC6E00BF30xD5A79147,
                0x6CA63510x142929670x27B70A850x2E1B21380x4D2C6DFC0x53380D13,
                0x650A73540x766A0ABB0x81C2C92E0x92722C850xA2BFE8A10xA81A664B,
                0xC24B8B700xC76C51A30xD192E8190xD69906240xF40E35850x106AA070,
                0x19A4C1160x1E376C080x2748774C0x34B0BCB50x391C0CB30x4ED8AA4A,
                0x5B9CCA4F0x682E6FF30x748F82EE0x78A5636F0x84C878140x8CC70208,
                0x90BEFFFA0xA4506CEB0xBEF9A3F70xC67178F2);
 
            var HASH = new Array(0x6A09E6670xBB67AE850x3C6EF3720xA54FF53A0x510E527F
0x9B05688C0x1F83D9AB0x5BE0CD19);
 
            var W = new Array(64);
            var a, b, c, d, e, f, g, h, i, j;
            var T1, T2;
      
            m[l >> 5|= 0x80 << (24 - l % 32);
            m[((l + 64 >> 9<< 4+ 15= l;
      
            for ( var i = 0; i<m.length; i+=16 ) {
                a = HASH[0];
                b = HASH[1];
                c = HASH[2];
                d = HASH[3];
                e = HASH[4];
                f = HASH[5];
                g = HASH[6];
                h = HASH[7];
      
                for ( var j = 0; j<64; j++) {
                    if (j < 16) W[j] = m[j + i];
                    else W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
      
                    T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
                    T2 = safe_add(Sigma0256(a), Maj(a, b, c));
      
                    h = g;
                    g = f;
                    f = e;
                    e = safe_add(d, T1);
                    d = c;
                    c = b;
                    b = a;
                    a = safe_add(T1, T2);
                }
      
                HASH[0= safe_add(a, HASH[0]);
                HASH[1= safe_add(b, HASH[1]);
                HASH[2= safe_add(c, HASH[2]);
                HASH[3= safe_add(d, HASH[3]);
                HASH[4= safe_add(e, HASH[4]);
                HASH[5= safe_add(f, HASH[5]);
                HASH[6= safe_add(g, HASH[6]);
                HASH[7= safe_add(h, HASH[7]);
            }
            return HASH;
        }
      
        function str2binb (str) {
            var bin = Array();
            var mask = (1 << chrsz) - 1;
            for(var i = 0; i < str.length * chrsz; i += chrsz) {
                bin[i>>5|= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32);
            }
            return bin;
        }
      
        function Utf8Encode(string) {
            string = string.replace(/\r\n/g,"\n");
            var utftext = "";
      
            for (var n = 0; n < string.length; n++) {
      
                var c = string.charCodeAt(n);
      
                if (c < 128) {
                    utftext += String.fromCharCode(c);
                }
                else if((c > 127&& (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6| 192);
                    utftext += String.fromCharCode((c & 63| 128);
                }
                else {
                    utftext += String.fromCharCode((c >> 12| 224);
                    utftext += String.fromCharCode(((c >> 6& 63| 128);
                    utftext += String.fromCharCode((c & 63| 128);
                }
      
            }
      
            return utftext;
        }
      
        function binb2hex (binarray) {
            var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
            var str = "";
            for(var i = 0; i < binarray.length * 4; i++) {
                str += hex_tab.charAt((binarray[i>>2>> ((3 - i%4)*8+4)) & 0xF+
                hex_tab.charAt((binarray[i>>2>> ((3 - i%4)*8  )) & 0xF);
            }
            return str;
        }
      
        s = Utf8Encode(s);
        return binb2hex(core_sha256(str2binb(s), s.length * chrsz));
      
    }
     
     
     
     
 
 
    // 암호화 확인
    console.log(SHA256("Test")) ;
 
</script>
 
cs

출처: http://fruitdev.tistory.com/191 [과일가게 개발자]




레퍼런스 문서

http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf

각 block 내용 및 W[64]의 내용들이 자세하게 나와있음

http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf

위와 비슷한 정보 

http://www.iwar.org.uk/comsec/resources/cipher/sha256-384-512.pdf



sha256은 hash 함수의 일종이다

hash 함수라는게 뭐냐면 다 알고 있겠지만 간단히 설명해보겠다


y = x + 2 이런 함수는 y를 알면 x도 알 수 있다

하지만 y = hash(x) 이런 해쉬 함수는 y를 알아도 x를 알 수 없는게 특징이다

그리고 모든 x값에 대해 각기 다른 y값을 내뱉는 특징 때문에 x가 원본임을 증명하는 일종의 시그니쳐로도 사용할 수 있다

(정확하게 말하자면 hash 함수는 단사함수가 아니다. hash collision이 있어서 다른 x임에도 같은 y값이 나오는 경우도 있다.

 hash collision을 피하기 위해선 계산을 더 복잡하게 하면 된다. 적당한 기회 비용을 두고 밀당을 해야한다는 소리)


hash 결과값은 32bit 8개를 병렬로 늘어놓은 값 

32bit x 8 = 256bit 그래서 이름이 sha256이다


원본 메세지의 각 문자(ascii 8bit)를 적당히 잘라 붙이고 쉬프트하고 and, or 등등 해서 512bit 단위의 블럭으로 만들고 이를 볶고 지져 hash를 계산한다

512bit 블럭으로 만들기 위해 크면 자르고(parsing) 모자라면 붙인다(padding)


아래의 공식에 맞춰 hash 계산에 필요한 블럭을 만든다

L + 1 + k = 448mod512


L(data length)는 hash를 만들고 싶은 원본 message의 bit길이 이므로 무조건 8의 배수이다

구현할 때 447bit 이런거 머리 빠지게 고민할 필요 없다


그리고 중요한 정보 - little endian을 기준으로 동작하도록 설계되어있다

x86, arm을 보통 사용하는 우리는 짜증나는 endian 전환을 해야 한다



실제 구현 관련 정리 - 블럭 제작 방법 및 hash 계산 방법

hash 계산 및 업데이트

간단하므로 생략, fips 문서에 나온데로 4개의 절차를 수행하면 된다(복잡해 보이는 시그마 같은거 다 문서에 잘 정의 되어있다)


메세지 길이 = len

case 1. len < 56(448bit)

마지막에 1bit를 추가하고 448bit까지 0으로 채움

그리고 마지막 64bit는 총 메세지 길이(lenx8)를 기록한다

hash 계산, 업데이트


case 2. 56 <= len < 64

마지막에 1bit를 추가하고 512bit까지 0으로 채워 block을 만든다

그리고 hash를 계산, 업데이트 한다

그리고 448bit까지 모두 0으로 채우고 마지막 64bit를 총 메세지 길이(lenx8)를 기록한다

그리고 hash 계산, 업데이트


case 3. len >= 64(512bit 이상)

512bit 씩 block으로 잘라 hash 계산, 업데이트 한다

마지막 남는 메세지는 길이에 따라 case1 혹은 case2와 동일하게 진행


last

계산한 32bit 8개의 값을 나열하면 sha256 완성



기타 유용한 참고 소스 코드

kernel 에 포함된 sha....코드.......이해하기 너무 어려움

openssl 의 crypto/sha에 있는 코드들 추천, 다만 최적화 되어있는 부분은 이해하기 힘듬

https://github.com/b-con/crypto-algorithms 매우 추천 깔끔하게 정리 되어있음

반응형

+ Recent posts