+++
date = 2021-07-09T10:24:00Z
description = ""
draft = false
slug = "cryptography"
title = "Cryptography"

+++


## **Cryptography**

### **공개키 암호화 알고리즘.**

#### 1.  Diffie-Hellman

디피-헬먼 키 교환 방식은 암호화 통신을 위한 키를 교환하는 방식 중 하나이다. 두 통신 주체가 공통의 비밀 키를 사용할 수 있도록 하는 안전한 알고리즘이다. 디피-헬먼 방식은 기초적인 암호 통신 방법으로, 이 알고리즘에 RSA나 ECC같은 암호화 알고리즘을 합쳐서 암호화 통신이 성립된다. 공개키는 암호화할 수 있는 키이고, 개인키는 복호화할 수 있는 키이다.

디피-헬먼 키 교환은 공개키 암호화 방식에 기반한다. 공개키 암호화 방식이란, 자신의 공개키를 상대방에게 전송하고, 그 상대방은 그 공개키로 데이터를 암호화해서 전송하면, 자신은 자신의 개인키로 복호화 할 수 있어, 통신이 성립되는 방식이다. 이때 상호통신을 위해서는 서로의 개인키를 공개키를 이용하여 공유하고, 각각 공유한 개인키와 공유키를 이용하여 공통된 비밀키를 계산하여 그것으로 통신하거나, 서로 각자의 개인키로 복호화하여 통신할 수 있다. 공통된 비밀키를 사용한다면 대칭 키 알고리즘, 서로 다른 키를 사용한다면 비대칭 키 알고리즘이라 한다.

디피-헬먼 키 교환 방식은 이산수학의 난해성에 기초한다. 먼저, 상호에 매우 큰 소수 P와 임의의 정수 N을 교환한다. 이는 공개적으로 전송해도 문제가 없다. 이때, 서로 P보다 작은 정수 a, b를 임의로 설정하고, N의 a, N의 b승의 mod P를 서로 전송한다. 이후에, 서로 전송받은 N의 b, a승 mod P를 자신이 가지고 있는 정수 a, b를 이용해 N의 b승의 a승과 N의 a승의 b승 mod P를 계산한다. N의 ab승과 N의 ba승은 지수법칙에 의해 동일하므로 이 값을 서로 공통의 비밀키로 사용할 수 있다.

위 상황에서 중간의 사람은 N과 P, N의 a, N의 b승의 mod P를 알 수 있다. 키 값을 알기 위해서는 N^ab mod P를 구해야 하는데, 이를 위해서는 a나 b 둘 중 하나는 알아야 한다. 여기서, 이산수학의 난해성에 의해 중간자는 a, b값을 알 수 없고, 이에 기밀성이 유지된다.

하지만, DH알고리즘은 가장 중요한 취약점이 있다. MITM공격에는 아주 무력하고, 기밀성만 보장할 뿐 무결성, 인증 등 기타 보안의 필수 조건을 만족시키지 못한다. 인증이란, 서로간의 정체를 확실이 하는가에 대한 문제이다. MITM 공격이란, 중간에 다른 사람이 송신자의 정보를 가로채고, 수신자에게 위조된 정보, 즉 자신의 계산값을 전송하는 상황에서 일어난다. 이때 수신자는 그 정보가 중간자가 아닌 송신자에게서 온 정보라 믿고 비밀키를 만들 것이고, 이에 중간자는 그 비밀키를 알게 된다. 받은 정보가 제대로 된 송신자에게서 온 정보인지 확신할 수 있어야 한다는 것이 인증의 개념인데, 디피-헬먼 키 교횐은 이러한 방법이 없다. 이러한 취약점을 해결하기 위해 DH와 RSA, ECDH등 다른 암호화 알고리즘과 합쳐서 PKI 등을 사용하는 것이다.

#### 2.  RSA

RSA는 일반적으로 알려져 있듯이 매우 큰 소수는 소인수 분해할 수 없다. (매우 힘들다)는 것을 기초로 하고 있다. RSA는 이 방식의 개발자인 세 사람 이름의 앞글자를 따서 만들어 졌다. RSA도 DH와 마찬가지로 공개키 암호화 알고리즘이다. 현재 인터넷에 사용되는 거의 모든 보안 체계는 RSA이며, 이는 RSA가 오랫동안 인정된, 안정적인 암호화 알고리즘이라는 뜻이다.

원리를 바로 설명하자면, 서로 각자 매우 큰 소수 p, q를 준비한다. (p-1), (q-1)과 서로소인 e에 대해, ed mod (p-1)(q-1)이 1인 d의 값을 찾고, N=pq와 e를 공개한다. 이들이 공개키가 되고, d는 개인키가 된다.

공개키 N, e로 평서문 m을 암호화하기 위해서는 m^e mod N을 계산하면 된다. 개인키 d를 가지고 있는 사람이 이를 복호화 하기 위해서는 $ (m^e)^d mod N $을 계산하면, m을 알아낼 수 있다. 이 고정에서 페르마의 소정리가 이용되는데, 페르마의 소정리란, 어떤 수 N이 있을 때, 이 수와 서로소인 수 a에 대하여,  $ a^{\phi(N)} = 1 \mod N $가 성립한다는 법칙이다. 이때 $ \phi(n) $은 오일러 파이 함수로, 1-N까지궁 N와 서로소인 수의 개수를 의미한다. N이 두 소인수로 이루어진 합성수라면, $ \phi(N) = (p-1)(q-1) $로 나타난다. 바로 이 값을 이용해서 복호화를 진행한다. $ E*d $ 는 $ (p-1)(q-1)A + 1 $ 로 나타낼 수 있고, 따라서 $ m^(ed) = m^(A(p-1)(q-1) +1) $인데, $ m^(p-1)(q-1) $은 1이므로, 이 값이 $m$이 된다.

$M^e mod N$과 $N, $e로는 원문 $m$과 개인키 $d$를 계산할 수 없다. 이를 계산하기 위해서는

RSA암호화 알고리즘과 DH알고리즘의 차이가 별로 없다고 생각할 수 있다. 뭐 알고리즘 상으로는 비슷하다. 다를게 없다. 하지만 제일 중요하게 다른 것은, RSA의 경우는 공개키와 비밀키를 메시지를 암호화할 때 사용한다는 것이고, DH는 개인키와 공개키를 이용하여 새로운 공통의 비밀키를 만든다는 점이다. 따라서, DH와 RSA의 차이는 키들의 용도이다. 애초에 DH는 키를 교환하는 방식이고 RSA는 암호화/복호화 알고리즘이니까 용도가 다르지만.

RSA도 마찬가지로 MITM에 매우 약하다. 오는 정보에만 의존해서 키를 사용하기 때문이다. 따라서 RSA도 인증의 면에서는 부족한 암호화 알고리즘이며, 이를 해결하기 위해서 PKI, Public Key Infrastructure를 사용한다. 이는 사람들의 공개키를 한 인증기관이 모아서 관리하여, 상호에 신원을 보장해주는 방식이다. 송신자는 이 인증기관에 수신자의 공개키를 조회하여, 제대로 된 공개키인지 확인할 수 있다. 하지만, 이러한 방식은 인증기관에 확인하는 과정이 필요하므로, 인증기관과 연결되어 있어야 한다는 점과, 이 과정에서 시간이 오래 걸린다는 단점이 있다.

이 점을 해결하기 위해 웹 보안에서 사용하는 HTTPS에서는 TLS/SSL이라는 더 응용한 암호가 적용된다. TLS는 상호 알고리즘 교환, 키 교환과 인증, 대칭키 생성과 통신이라는 세 단계로 나누어 통신한다.

#### 3.  ECC

ECC는, Elliptic Curve Cryptography로, 타원곡선 이론에 기반한 암호화 알고리즘이다. RSA에서는 소수를 사용했다면, ECC에서는 GF에서 EC연산의 비가역성을 이용한다. EC는 RSA보다 키의 길이가 짧아도 보안성이 우수하며, 연산 시간이 더 짧다는 장점이 있어, 블록체인이나 IoT 보안 등 현재의 암호에는 ECC가 주로 사용된다.

타원곡선이란 무엇일까? 타원곡선이란, _ y2=x3+Ax+B_ 의 형식으로 나타나는 음함수이다. 타원곡선은 타원의 둘레를 계산하기 위해 타원을 적분하려다 나타난 식이라고 하는데, 그 함수의 역함수가 위의 형식이라고 한다. 더 자세하게 말하면, 체 k에서, 타원곡선은 특정 조건들을 만족시키며 원점이 주어진 k에 대한 사영 대수 곡선이다. 첫번째 특이점을 가지지 않으며, 둘째 위상수학적으로 원환면이며, 셋째 적어도 하나의 유리점을 가진다는 조건이다. 하나하나씩 알아보자.

체는 무엇이고, 사영 대수 곡선이란 말은 어떤 말일까?

일단 체(Field)란, 사칙연산(덧셈, 뺄셈, 곱셈, 나눗셈)에 대해 닫혀있는 집합을 의미한다. 이는 하나의 체 안에 있는 원소들끼리 사칙연산을 해도 그 값이 체 안에 속해있다는 의미이다. 가장 대표적인 체는 유리수 집합, 실수 집합, 복소수 집합이 있다.

즉, 체 k에서 특정한 조건을 만족시키며 특정 원점을 가지는 대수 곡선이라는 의미는, 위에서 언급했던 타원 방정식을 만족시키면서 A, B로 표기되어 있는 계수가 하나로 정해져 있는 점들의 집합을 의미한다. 타원 곡선이 체라고 하는 이유는, 타원 곡선에서 새롭게 정의한 덧셈을 이용해 서로 다른 점끼리 덧셈을 하면, 타원곡선 위에 있기 때문에, 사칙연산에 대해 닫혀있기 때문이다. 타원 곡선을 어떤 체 위에서 정의하느냐에 따라 달라지겠지만, 암호학에서 사용할 때에는 정수 위에서 정의하는 것으로 하자. 정수는 체가 아닌데요?라는 의문을 가진다면, 정수의 나눗셈을 해결할 수 있는, 모듈러 연산을 이용한 갈루아체 위에서 정의한다고 알아두자, 이는 나중에 설명하겠다. 타원 곡선상의 덧셈의 특징을 설명하기 전에, 무한점 O에 대해 설명하겠다. 무한점 O는 말 그대로 타원곡선 상에서 무한대로 극한을 보냈을 때의 점을 의미한다. 무한점은 타원곡선 상의 점A에 대해 (앞으로 점 A라고 하면 타원곡선 위에 있는 점을 의미한다.) A+O=A를 만족시킨다. 따라서, 타원곡선 체에 대해서 무한점O는 항등원이다. 또한, 점P와 점Q에 대해서 P+Q=O를 만족시키는 점 Q는 점P에 대한 역원이고, Q=-P로 표현할 수 있겠다. 이때, -P는 P를 x축 대칭한 점이 된다. 또한 교환법칙도 성립한다. 뭐라해도 타원곡선은 체이니까 말이다.

그렇다면 타원곡선 위에서 덧셈을 정의하자. 덧셈을 정의하면 곱셈이나 뺼셈이 정의되고, 그렇면 나눗셈도 정의된다. 점P를 (P_x, P_y)라 하고 마찬가지로 점Q를 (Q_x, Q_y)라고 하자. 특이하게도 타원곡선 상의 덧셈은 두 점이 같은 경우와 다른 경우를 나누어서 정의하는데, 그래도 쓰면 무한점이 나오기 떄문이다.

If P=Q, P+Q = 2*P

If P!=Q, P+Q = (,)

이 연산을 타원연산의 덧셈으로 정의한다. 곱셈은 덧셈을 여러 번 하면 되고, 나눗셈은 갈루아 체에서 정의되는 대로 역모듈러 연산을 사용한다.

타원 곡선 암호는 RSA에서 소인수분해의 난해성을 이용한 것 처럼 타원곡선에서 갈루아 소수가 커질 경우 x값을 만족시키는 y의 값을 찾기 힘든 점을 이용한다. 갈루아 소수란, 갈루아 체에서 이용하는 소수로, 모듈러 상수를 의미한다.

ECC는 RSA와 다르게 개인키를 먼저 생성한다. 갈루아 소수 P를 상호에 정하고, 송신자는 P보다 작은 한 소수 k를 임의로 정한다. 후에, 생성자라고 불리우는 상호 동일한 타원곡서 상의 임의의 점 G에 대해 k*G를 연산하면 그 값이 공개키 Q가 된다. k*G는 계산하기 쉬운 반면에 갈루아 체에서는 G와 Q를 이용해 k를 구하기 어렵다는 점을 이용한다.

ECC는 RSA에 비해 반절정도로 작은 키로 같은 보안을 얻어낼 수 있다. 하지만, ECC도 취약한 부분이 존재하는데, 임의의 소수를 정하는 데에 그것이 있다. 만약 그 난수를 구하는 알고리즘이 유출된다면 ECC는 무용지물이 되기 때문이다. 실제로, ECDSA를 이용하는 서명 체계에서 난수 생성 알고리즘이 알려져 무용지물 된 사건이 있었다. 따라서, 현재는 밀러-라빈 후보와 오일러 판정법을 이용하여 임의의 소수를 도출하거나, 하드웨어적으로 블랙박스안에 넣는 방식으로 이를 방지한다.

ECC에서 사용하는 타원 곡선의 종류에 따라 암호화 알고리즘을 나눈다. 비트코인에서 주로 사용하는 것으로 유명한 secp256k1 곡선도 있고, 생성자와 갈루아 소수를 정해놓지 않고 이것도 임의의 t로 교환하는 방식으로 이것에서 보안을 더 높인 SECP256R1 곡선을 이용한 암호도 있다. P256은 256비트짜리 소수를 이용한다는 의미이고, k는 곡선 y^2 = x^3 + 7을 의미, r은 random을 의미한다.

ECC는 개인키, 공개키 발급 방식 중 하나이고, DH과 ECC를 엮어서 만든 암호화 방식이 ECDH이며, ECC와 서명 알고리즘을 엮은 것이 ECDSA이다.


### **블록 암호화 알고리즘. (Block Cipher Algorithms)**

#### 1.  DES (Data Encryption Standard)

DES는 64비트 블록을 사용하는 대칭키 블록 암호 알고리즘이다. 암호화 과정은 16 라운드의 Feistel 구조를 기반으로 한다. 각 라운드에서는 데이터는 48비트 서브키(subkey)를 사용하여 변형된다.

Key Schedule Algorithm: 
- 초기 64비트 키에서 parity check bits를 제외해 56비트로 압축한다.
- 압축된 키는 28비트로 두 개의 반으로 나뉜다. $( C_0, D_0 )$
- 각 라운드마다 $C_i$와 $D_i$는 라운드에 따라 정해진 수만큼 왼쪽으로 이동(rotated)한다.
- 회전 후의 $C_i$와 $D_i$는 결합되어 56비트가 되고, 48비트 서브키를 생성하기 위해 압축 퍼뮤테이션이 적용된다.

Encryption Operation:
- 초기 평문은 Initial Permutation (IP)을 통해 재배치된다.
- 재배치된 평문은 32비트의 두 부분인 $L_0$과 $R_0$으로 나뉜다.
- 각 라운드에서 $L_{i+1} = R_i$과 $R_{i+1} = L_i \oplus f(R_i, K_i)$를 계산한다. 여기서 $\oplus$는 bitwise XOR 연산자이고, $f$는 Feistel function, $K_i$는 $i$번째 라운드의 서브키다.
- 마지막 라운드 후, 결과는 $R_{16}L_{16}$ 순서로 조합되고 Final Permutation (FP)을 통해 최종 암호문을 생성한다.

Feistel Function:
- $f(R_i, K_i)$는 확장 퍼뮤테이션으로 시작하여 $R_i$를 48비트로 확장한다.
- 확장된 $R_i$는 서브키 $K_i$와 XOR 연산된다.
- 결과는 S-box lookup table을 통해 각각 6비트가 4비트로 변환된다.
- S-box 변환 후 32비트 나온 결과에 비선형 변환이 P-box permutation으로 수행된다.

DES의 보안은 같은 키를 사용해서 여러 데이터를 암호화하는 경우와 56비트 키 길이가 가지는 제한된 키 공간 때문에 줄어들었다.

#### 2.  AES (Advanced Encryption Standard)

AES는 128, 192, 혹은 256비트 키를 사용하여 128비트 데이터 블록을 암호화한다. AES의 구조는 Rijndael 암호에 기초를 두고 있으며, 라운드 수는 키 길이에 따라 달라진다 (10, 12, 또는 14 라운드).

Key Expansion:
- 라운드 키 생성에 사용되는 Rijndael 키 스케줄은 $W[i-1]$ 에 비선형 변환과 상수의 XOR 연산을 적용하여 $W[i]$ 를 생성한다.
- 라운드 상수는 $RC[j]$로 표현되며, 이는 $x$의 멱도로 구성된다. $x$는 갈루아 체 $GF(2^8)$의 생성원이다.

$$
W[i] = W[i-Nk] \oplus \text{SubWord}(W[i-1]) \oplus RC[j]
$$

여기서 $Nk$ 는 키 길이에 따른 워드 수 (4, 6, 또는 8), $RC[j]$ 는 라운드 상수, $\text{SubWord}()$ 는 S-box 변환을 적용한 함수이다.

Encryption Process:
- 평문은 AddRoundKey 스텝을 통해 초기 라운드 키와 XOR 연산된다.
- 각 중간 라운드에서는 SubBytes (byte 치환), ShiftRows (행 이동), MixColumns (열 혼합), AddRoundKey (라운드 키 가산) 연산이 순차적으로 수행된다.
- 마지막 라운드에서는 MixColumns 스텝이 생략된다.

SubBytes:
- 비선형 S-box 변환은 각 바이트를 갈루아 체 $GF(2^8)$ 의 역원을 구한 후, 아핀 변환을 적용하여 새로운 바이트로 치환한다.

$$
\text{SubBytes}(a) = \text{Affine}(\text{MultiplicativeInverse}(a))
$$

ShiftRows:
- 행 별 이동은 사이클릭 퍼뮤테이션을 적용하여 암호화 과정에 확산성을 부여한다.

MixColumns:
- 각 열은 다음 다항식과의 $\text{mod}\ x^4 + 1$ 에서 곱셈 연산을 통해 변환된다.

$$
\begin{bmatrix}
02 & 03 & 01 & 01\\
01 & 02 & 03 & 01\\
01 & 01 & 02 & 03\\
03 & 01 & 01 & 02
\end{bmatrix}
\cdot
\begin{bmatrix}
b_0\\
b_1\\
b_2\\
b_3
\end{bmatrix}
$$

여기서 $b_0, b_1, b_2, b_3$은 현 열의 바이트이며, 행렬 연산은 $GF(2^8)$ 상에서 수행된다.

AddRoundKey:
- 각 라운드 키는 현재 상태와 다음과 같이 XOR 연산된다.

$$
\text{State} \oplus \text{RoundKey}
$$

AES는 모듈러 산술과 갈루아 체(Galois field)를 사용하여 비선형 및 확산적 특성을 갖는다.

#### 3.  SEED

SEED는 한국 인터넷진흥원(KISA)에 의해 개발된 128비트 블록 암호 방식으로, 128비트 키를 사용하며 16 라운드의 Feistel 구조를 따른다.

Encryption Process:
- 128비트 키는 16개의 64비트 서브키로 확장된다.
- 초기 평문 블록은 키와 Feistel 네트워크를 통해 가공된다.
- 각 라운드의 결과는 두 반으로 이뤄져 있고, 지정된 함수를 통해 연산된 다음, 키와 XOR 연산된다.
- 키 확장 과정에서 사용되는 상수는 일련의 알고리즘을 통해 생성되며, 이는 SEED의 보안성을 향상시킨다.

$$
K_i = f(K_{i-1}), \quad \text{where } i = 1, 2, \ldots, 16
$$

여기서 $f()$ 는 키 확장 함수, $K_i$ 는 $i$번째 라운드의 서브키이다.

Feistel Function:
- SEED의 Feistel 함수는 S-box를 통한 비선형 변환과 $GF(2^{32})$에서의 변환을 결합하여 사용한다. S-box의 비선형 특성과 더불어 선형 변환은 암호화 과정에 확산성과 혼돈성을 주입한다.

각 라운드에서의 연산은 다음과 같은 수학적 표현으로 이루어진다.

$$
\text{left} = \text{right}
$$
$$
\text{right} = \text{left} \oplus F(\text{right}, K_i)
$$

여기서 $F()$ 는 Feistel 함수, $K_i$ 는 라운드 서브키이며, $\text{left}$와 $\text{right}$는 데이터 블록의 두 부분을 의미한다.

SEED는 높은 보안성과 우수한 성능으로 인해 South Korea 전자정부 및 인터넷 은행 거래에 사용된다.

#### 4.  PRINCE

PRINCE는 저전력 환경에 최적화된 경량 블록암호로 AES와 마찬가지로 여러 개의 라운드로 구분된다. Mix Column부터 ShiftBits까지 AES와 매우 비슷하지만, 연산을 더욱 간단화하고 라운드 수를 줄여 저성능 프로세서에서도 많은 비용과 시간을 들이지 않고도 암호화, 복호화를 진행할 수 있도록 한 암호화 방식이다. 기초적인 것들은 AES와 비슷하므로 바로 암호화, 복호화 과정을 살펴보자. 여기서는 PRINCE-64/128을 기준으로 설명할 것이다. 128bit 비밀키를 이용하여 64비트 키로 분할하여 사용한다는 의미이다.

PRINCE의 구조는 12 라운드로 구성되며, 상호 역변환되는 라운드 함수를 사용한다.

Encryption/Decryption Process:
- PRINCE 알고리즘은 암호화와 복호화 과정이 매우 유사하며, 라운드 키 스케줄이 역순으로 구성된다.
- PRINCEcore는 중심 라운드로, 여기에서 상태는 여섯 개의 서브 라운드를 계속 거친다.
- 암호화와 복호화는 대칭적인 알파(reflection) 구조를 갖는다. 즉, 전반부와 후반부 라운드가 서로 역변환된다.

Key Schedule:
- 키 스케줄에서, 128비트 키는 두 개의 64비트 부분 키로 나뉘며, 알파 상수를 사용하여 변형된다.

S-box-based Nonlinear Layer:
- PRINCE 알고리즘은 비선형성을 부여하기 위해 S-box를 사용한다.

M-Layer (Linear Transformation Layer):
- 이 선형 변환층은 확산을 증대시키기 위해 사용된다.

위 과정을 통해서 암호화하는 알고리즘을 4-Round 알고리즘이라 하며, 표준 Prince알고리즘은 총 12-Round를 사용한다. 이처럼 연산의 용이성을 위해 라운드를 줄인 Prince를 Round-Reduced Prince라고 한다.
PRINCE 알고리즘은 그것의 반사성(reflection property) 덕분에, 암호화 구조가 복호화 구조를 간단하게 반전시키는 방식으로 구현될 수 있다는 점에서 하드웨어 구현 시에 에너지 효율성을 높여준다. 하지만, 4-Round PRINCE-64/128 나 6-Round PRINCE-64/128는 고정키 대입 공격등 Side-Channel 공격에 면역이 없기 때문에 IoT나 소형 기기에서는 적당히 타협하여 12-Round PRINCE-64/128를 사용 한다.


### **해시 알고리즘. (Hash Algorithms)**

#### 1.  MD5 (Message-Digest Algorithm 5)

MD5는 512비트 메시지 블록을 다루고 128비트 해시 값을 생성한다. MD5의 구성은 다음과 같다:

Process:
- 입력 메시지는 512비트 블록으로 나뉜다.
- 각 블록은 압축 함수와 초기 해시 값(또는 이전 블록의 결과)에 의해 처리된다.
- 압축 함수는 네 개의 사이클을 사용해서 각 블록을 처리한다.

Compression Function:
- 각 사이클은 S-box와 비선형 함수를 사용하며 메시지 블록과 현재 해시 값을 기반으로 연산을 수행한다.
- 출력은 이전 해시 상태와 더해진다.

MD5는 충돌 공격에 취약하기 때문에 현재 보안이 중요한 용도에는 권장하지 않는다.

#### 2.  SHA (Secure Hash Algorithm)

SHA 패밀리는 다양한 해시 함수들을 포함한다 (SHA-0, SHA-1, SHA-2).

SHA-1 Process:
- 메시지는 512비트 블록으로 나뉘고 블록마다 압축 함수를 사용해 160비트 해시를 계산.
- 각 블록은 특정한 비선형 기능과 함께 반복된다.

SHA-2 Variants (SHA-256, SHA-512 등):
- SHA-2는 무결성 보장 목적에 사용, 더 긴 해시 값과 변형된 알고리즘을 포함.
- SHA-256은 32비트 워드, SHA-512는 64비트 워드를 사용한다.

Compression Function:
- 체인화된 값과 야수 상수를 사용한 라운드 함수.
- 메시지 스케줄, 라운드 상수, 라운드 함수, 중간 상태 갱신을 통한 해시 생성.

SHA 알고리즘들은 다양한 애플리케이션에서 널리 사용되며, 특히 SHA-256과 SHA-3은 현재 많이 사용된다.

#### SHA-1

SHA-1 해시 함수는 메시지 $ M $을 160비트의 해시 값으로 매핑한다.

Initialization:
- 초기 해시 값 $ H^{(0)} $는 5개의 32비트 워드 $ H_0^{(0)}, H_1^{(0)}, H_2^{(0)}, H_3^{(0)}, H_4^{(0)} $로 설정된다.

Message Preprocessing:
- 입력 메시지 $ M $은 512비트 블록들로 나누어지고, 패딩과 길이 인코딩을 거쳐 $ L $ 비트의 메시지가 된다.
- 각 블록에 대해, 80개의 32비트 워드 $ W $로 확장된 메시지 스케줄이 생성된다.

Hash Computation:
- 각 라운드 $ t $에서 다음의 연산을 수행한다:
  $$ T = (H_0 \lll 5) + f_t(H_1, H_2, H_3) + H_4 + W_t + K_t $$
  $$ H_4 = H_3 $$
  $$ H_3 = H_2 $$
  $$ H_2 = H_1 \lll 30 $$
  $$ H_1 = H_0 $$
  $$ H_0 = T $$
  여기서 $ f_t $는 라운드에 따라 변하는 논리 함수이며, $ K_t $는 라운드 상수이다.

#### SHA-256

Initialization:
- 초기 해시 값 $ H $는 $ H_0 $부터 $ H_7 $까지의 8개의 32비트 워드로 구성되며, 이는 특정 소수의 제곱근에서 파생된다.

Message Preprocessing:
- 입력 메시지 $ M $은 512비트 블록들로 나누어지며, 패딩 및 길이 인코딩을 거쳐 메시지 스케줄 $ W $로 변환된다.
- $ W $는 64개의 32비트 워드로 확장되며, 각 $ W_t $는 $ M $의 해당 부분과 앞선 워드들의 비선형 함수 $ f $에 의해 계산된다.

Hash Computation:
- 메인 루프는 $ H $를 업데이트하기 위해 64회의 라운드를 수행한다.
- 각 $ t $번째 라운드에서, 다음과 같은 수학적 연산이 수행된다:
  $$ T_1 = H_7 + \Sigma_1(H_4) + \text{Ch}(H_4, H_5, H_6) + K_t + W_t $$
  $$ T_2 = \Sigma_0(H_0) + \text{Maj}(H_0, H_1, H_2) $$
  여기서 $ \Sigma_0, \Sigma_1 $은 각각 회전 및 오른쪽 시프트 연산으로 정의되며, $ \text{Ch} $와 $ \text{Maj} $는 입력 워드들의 비트를 선택하는 논리 함수이다.
- 그 후, 중간 해시 값 $ H $는 다음과 같이 업데이트된다:
  $$ H_7 = H_6 $$
  $$ H_6 = H_5 $$
  $$ H_5 = H_4 $$
  $$ H_4 = H_3 + T_1 $$
  $$ H_3 = H_2 $$
  $$ H_2 = H_1 $$
  $$ H_1 = H_0 $$
  $$ H_0 = T_1 + T_2 $$

SHA-256의 모든 수학적 변환은 $ \text{GF}(2^{32}) $상에서 수행되며, $ K_t $는 각 라운드에 고유한 상수이다. SHA 알고리즘은 입력 메시지의 아주 작은 변화도 출력 해시 값에 큰 변화를 가져오는 "avalanche effect"를 만들어내는 설계 원리를 가지고 있다.

#### 3.  HMAC (Hash-Based Message Authentication Code)

HMAC은 해시 알고리즘 위에 구축된 메시지 인증 코드 (MAC) 프로토콜이며, 키와 메시지 모두를 기반으로 한 인증 태그를 생성한다.

HMAC Process:
- 키와 함께 초기화 벡터(IV)를 사용하여 해시 함수에 입력.
- 두 단계 과정:
  - 내부 해시($H(K \oplus ipad \parallel m)$)는 입력 메시지 m과 패딩이 적용된 키 K를 사용.
  - 외부 해시($H(K \oplus opad \parallel inner)$)는 내부 해시 결과에 다시 패딩이 적용된 키 K를 사용.

여기에서 $ipad$, $opad$는 특정한 패딩 값을 가리키고, $H$는 해시 함수, $K$는 비밀 키, $\parallel$는 이어붙이기 연산자다.

- 주어진 메시지 $ M $과 비밀 키 $ K $에 대해, HMAC은 다음과 같이 계산된다:

  $$ \text{HMAC}(K, M) = H((K' \oplus opad) \text{concat} H((K' \oplus ipad) \text{concat} M)) $$
  여기서 $ H $는 해시 함수, $ K' $는 원래 키 $ K $를 내부 블록 크기에 맞게 조정한 것, $ opad $와 $ ipad $는 각각 외부 및 내부 패딩이다.

HMAC은 키와 긴 메시지를 사용한 메시지 인증, 데이터 무결성, 데이터 출처 인증에 사용된다.