비대칭키를 이용한 암호/서명

- 비대칭키: 개인키 및 공개키로 나누어 활용

- 공개키: 암호화 작업만 할 수 있음. 누구에게나 공개되어도 상관 없음

- 개인키: 복호화 작업을 위해 사용. 공개되면 안되는 키

디지털 서명

- '원래 자료'를 '해쉬'로 만든 다음,

- ‘개인 키'로 해당 해쉬 값을 ’암호화' 하고 (서명),

- 다른 사람들은 '원래 자료'를 '해쉬'로 만든 다음,

- 서명 값을 '공개 키'로 '복호화' 해서 비교하여

- 두 해쉬 값을 비교하여 일치하면 서명이 유효함.

즉 인증서를 통한 로그인시

- 사용자: 인증서의 고유 번호 + challenge 받은 메시지에 대한 서명 값을 server로 전송

- 서버: 해당 고유 번호에 등록된 공개키로 이 사용자가 서명한 값이 맞는지 확인 (검증은 공개키로 가능. 검증에 성공했다는 것은 이 사용자가 개인키를 가지고 있다는 이야기)

(실제 서버단에서는 어떤 다른 추가적인 방법이 있는지는 알 수 없으나 아무튼 정해서

공인인증서 관련 기술들

- http://www.rootca.or.kr/kor/standard/standard01B.jsp 를 참고

- 개인키: signPri.key 에 암호화 되어 들어있다.

- 공개키: signCert.der 에 들어있다.

- 인증서 발급처 마다 조금씩은 다르지만, 은행에서 발급 받은 yessign 공인인증서를 이용하여 테스트

공개키 파일

- signCert.der

- asn1 형식

- 안에 다시 asn1 형식

- 해당 파일이 PKCS#1인데 pub key 만 있었음

개인키 파일

- signPri.key

- PKCS#5 의 PBKDF1방식을 이용하여 복호화 한다. (키 파일에서 salt, integration count 를 구하고, 비밀번호는 공인인증서 비밀번호)

위 두 파일에 대한 처리 방법은 아래 링크를 참고

- https://gist.github.com/twkang/f5acf360c67ea0bf3f55

 

테스트해봅시다.

(파이선 코드)

원본(3): “abc”

sha256(64H/32B) ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

EME-PKCS1-v1_5 padding 처리 (msg = ‘abc’, key 길이 = 256, hash=sha256)

0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

(앞에 \x00\x01 붙이고, \xff로 쭉 채우고 \x00 붙이고 해쉬 종류에 따른 prefix 붙이고 abc에 대한 해쉬값을 붙인다.)

이 값을 개인키를 이용하여 ‘복호화’ 한다.

(암호화도 안했는데 왜 복호화부터 하냐고 묻지말자. 그냥 이렇게 정한것이다. 정말 PKI기반 디지털 서의 이론적인 원리가 궁금하다면 http://en.wikipedia.org/wiki/Digital_signature#How_they_work 를 참고하자.)

-> (256바이트/512Hex 데이터)

이 값이 서명값이고, 실제 플러그인에서 만들어 낸 서명문의 서명값과 일치한다.

(실제 플러그인 구동)

원본: SignData(‘abc’,’’,0)

결과값(3760H):

-> 3082...

여기서 뽑아낸 hash (512H/256B)

-> 26...76

이 hash에 대한 pubkey의 encrypt 결과 (510H/255B)

-> 01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

서명(sign) : 복호화(decrypt)

검증(verify) == 암호화 후 메시지 같은지 비교

<실험>

서명 데이터를 다르게 했을 때 두 값이 달랐는데, 하나는 pkcs7-data(이게 아마 format에 맞춘게 아닐까), 나머지 하나가 해쉬.. 근데 그러면 pkcs7-data를 sign해야되나...

#1 mitmproxy 를 이용하여 트래픽 분석

#2 트래픽 일부 분석

#3 인증서 구조 분석

#4 서명 결과 분석

- ***** 사이트에서 로그인 시도

- yessignCrypto.js 스크립트에서 서명

- inputStr 에 서명할 데이터 포함 (timestamp 포함한 form data)

- yessignCrypto.SignData(inputStr, ssn, option) 을 통해 서명 (ssn, option에는 blank string)

- 공인인증서 로그인 창이 뜬 다음 서명 데이터 나온다 (여러번 요청해도 똑같은 데이터가 나옴 - 즉 서명 단계에서는 더이상 랜덤 값을 넣지 않는다)

- 이 결과(A)에 몇 가지 form data 를 추가하여 POST 요청

#5 결과(A)에 대한 분석

- 길이는 3966 바이트 (어느정도 변화 가능 - hex encoded 데이터)

- hex decode 결과는 약 1983 바이트 결과(A-1)

- 결과(A-1)은 30 82 로 시작하는 0x3082 == ASN.1 Sequence (http://etherhack.co.uk/asymmetric/docs/rsa_key_breakdown.html)

- 이 결과(A-1)를 파일로 저장하여 openssl 로 열어봅시다

- $ openssl asn1parse -in FILENAME -inform der

- pkcs7-data 로 174바이트의 hex encoded 데이터 (hex decode 후 euc-kr 로 decode시 원본 서명 텍스트 나옴)

- rsaEncryption 로 512바이트의 hex encoded 데이터 (hex decode 후 256바이트의 raw data)

- sha256WithRSAEncryption 로 2048비트(256바이트)의 이진수 데이터 (raw data). RSA암호 후 이걸로 해쉬하면 이게 나오나

- 특별히 이름은 없는데 270바이트짜리 2진수 raw data도 존재. 서명 단계에서 원본값을 변조한 결과 변경되지 않으므로 무시.

- 즉 sha256WithRSAEncryption 값이 서명 데이터임을 알 수 있음

#6 서명데이터(256바이트)에 대한 분석

- object tag를 통해 active x 를 호출하는 과정에서, 같은 인증서를 이용한 경우 해쉬 값에는 오로지 메시지만 영향을 주는 것을 확인

-> 즉 메시지에 대한 서명값

#* 기타

- 전자 서명문은 PKCS#7 을 이용

Posted by Parker Falcon