본문 바로가기
개발Study/보안

SSH key generator - passphrase

by happy90 2021. 4. 4.
SMALL

RSA 암호화방식은 비대칭 암호화방식으로써, 암호화하는 키와 복호화하는 키를 별도로 둔다.

RSA방식으로 암호화 키를 생성하면 공개키/비공개(public/private key)키 두 개가 생성된다.

공개키는 암호화할 때 사용하고, 비공개키는 복호화할 때 사용한다.

 

그런데, 이 key들은 파일로 저장되기 때문에 어떤 원인에 의해 외부로 유출될 가능성이 있다.

물론 하나만 유출되면 문제될 일이 없겠지만, private key까지 유출되면 보안이 뚫리게 되는 것이다.

그래서 이 private key를 암호화하여 보관할 수 있는데, 이 때 사용되는 것이 passphrase이다.

passphrase는 단어 그대로 "암호"이다.

공격자의 유추가 힘들고 공격에 많은 시간이 소요되도록 암호를 생성하는 방법이다.

 

 passphrase는 단순히 "암호"로서의 기능을 한다. 이 암호를 이용하여 private key를 암호화할 때에는 bcrypt 해쉬를 이용한다. 암호화시 랜덤의 salt값을 생성하고, 이를 이용하여 passphrase를 특정 round수 만큼 해시한다. salt 또한 동일한 횟수로 해시한 후 bcrypt해쉬를 이용해 또 한번 해쉬한다. 이 결과물이 private key를 암호화할 때 사용되는 key가 되는 것이다. 복잡..

 

 어떤 업무때문에 널리 쓰이는 이 openssh의 rsa key 암호화 방식의 소스코드를 분석하여 제출해야 하는 상황이 발생했다. openssh를 이용하고, key관리는 이렇게 됩니다. 정도의 설명으로 끝나면 얼마나 좋을까. 모르는 소스코드도 아니고, 오픈소스인데 굳이 이걸 설명하라고... 정말 비효율적인 기관이지 않나 싶다. 내 공부한다 생각하면서 분석했다.

 

key 생성시 입력받은 passphrase을 이용하여 private key를 암호화하는 소스코드 설명

참조 : cdn.openbsd.org/pub/OpenBSD/OpenSSH/openssh-8.5.tar.gz

openssh 코드라면 어떤 버전이든 동일하거나 비슷할 것이다.

 사용자로부터 Passphrase를 입력받은 후 sshkey_save_private를 실행한다. 이 함수 인자에 입력되는 identity_file이 최종 key를 저장할 file명이다.


 위 함수에서 sshkey_private_to_fileblob에서 암호화를 진행하고, sshkey_save_private_blob에서 암호화된 private key를 저장한다. keyblob에 최종 저장될 key 내용이 담긴다.


1) 암호화 부분:

 

위 코드의 sshkey_private_to_blob2에서 실제 암호화를 진행한다.


sshkey_private_to_blob2 function:
초기화 부분. 암호화에 필요한 버퍼 및 변수들을 초기화한다

 

 bcrypt방식으로 passphrase를 hashing한다. bcrypt방식은 pbkdf보다 강력하며 주로 password암호화를 위해 사용된다. random값 salt생성 후 bcrypt_pbkdf함수에 전달하여 해시가 진행된다. bcrypt_pbkdf함수에서 해싱된 passphrase는 해당 함수 5번째 인자 pointer key가 가리키게 된다.이후 kdf에 salt, rounds를 기록하고, ciphercontext에 해싱된 passphrase와 salt등 정보를 셋팅한다.  
 최종 private key 파일에 쓸 버퍼(encoded)에 AUTH_MAGIC, ciphername, kdfname, kdf, 1(numberOfKeys), public key를 차례대로 쓴다. 아래는 그 코드이다.
 sshbuf_put~의 형태로 된 함수들은 주어진 버퍼에 값을 쓰기 위한 함수이다. 이를 참고하여 passphrase를 hash한 뒤 sshbuf 함수를 이용해 어딘가에 쓰는 동작은 하지 않는 것을 확인할 수 있다. bcrypt_pbkdf의 결과로 hash된 passphrase를 가리키는 포인터 key 또한 다른 버퍼에 쓰이지 않는다. ciphercontext를 통해 암호화할 때에만 사용된다.

 해싱한 passphrase와 salt값을 이용하여 private key를 암호화한다. 앞에서 생성한 버퍼(encoded)에 암호화한 private key를 붙여넣고, 포인터 blob에 최종 private key file 형식으로 넣어준다.

 

 아래는 sshkey.c에 정의된 매크로이다. 암호화방식을 별도로 설정하지 않으면 default AES256-CTR 방식으로 암호화가 진행된다. 해당 코드는 위 sshkey_private_to_blob2 함수의 ciphername을 설정하는 부분에서 확인할 수 있다.


위의 암호화 결과로 나온 keyblob을 file에 쓰는 함수:

 

passphrase를 이용하여 암호화된 private key의 복호화

 위 함수의 인자 filename은 private key file name, passphrase는 사용자로부터 입력 받은 passphrase이다.


 sshbuf_load_fd 함수에서 file을 buffer에 읽어오고, sshkey_parse_private_fileblob_type함수에서 passphrase의 일치 여부를 확인한다. 아래 함수의 sshkey_sshkey_parse_private2함수에서 passphrase를 이용해 복호화를 진행한다. 복호화 결과를 blob에 저장한다.


Private key를 parsing하는 함수.


 
Private key를 복호화하는 함수


 
 먼저 key file을 읽어온 버퍼에서 ciphername, kdfname, kdf, number of key 값을 파싱하여 가져온다. Private key 암호화 코드에서 살펴봤듯이 값들은 암호화된 private key와 함께 저장되어 있다. 
 private key에 암호화가 되어있는지 확인하고, 암호화가 되어 있다면 복호화를 하기 위해 버퍼 및 변수 설정을 진행한다. key file에서 읽은 salt값과 사용자로부터 입력받은 passphrase를 이용하여 private key를 bcrypt 해싱한다. 해싱결과로 나온 passphrase로 private key를 복호화한다.

 

Check byte를 확인하고 decryptedp에 복호화된 private key를 넘겨준다. Pubkeyp에 public key를 넘겨준다.

 

 

 

LIST

댓글