블록체인 기반 서비스 개인키 관리 가이드라인
A. 암호키를 위한 보호 요구사항(protection requirement) - 디지털 서명 개인키
- Security Service: 디지털 서명 알고리즘 → 출처인증, 무결성 보장, 부인방지의 보안 서비스 제공
- Security Protection: 개인키의 안전성을 위한 보호조치 → 기밀성, 무결성
- Association Protection: 개인키의 안전성을 위해 키와 연관되어 함께 보호되어야 하는 대상
→ 키의 사용 혹은 응용과정, 서명 과정에서 필요한 도메인 파라미터, 공개키 - Assurances Required: 공개키 유효성의 보장 혹은 개인키 보유에 대한 보장의 필요 여부
→ 개인키 사용 시점에 실제 사용자에 의해 사용되었음에 대한 보장 - Period Protection: 개인키 보호조치 필요 기간 → 개인키 생성 ~ 폐기 시점
B. 개인키 보호에 필요한 속성
- 가용성(availability): 키 정보는 암호키가 사용 되는 동안 쉽게 사용될 수 있어야 한다.
→ 키 복사본을 하나 이상 만들어 별도의 위치에 보관 권고 - 무결성(integrity): 키 정보에 대한 수정 방지/탐지, 승인되지 않은 수정에 대한 키 정보 복원
- 물리적 메커니즘
- 저장된 키 정보에 대한 임의 접근을 제한하는 검증된 암호 모듈 혹은 운영체제
- 다른 시스템에 연결되지 않은 독립된 시스템
- 시스템 외부에 적절한 접근 제어를 갖춘 물리적으로 안전한 환경 - 암호학적 메커니즘
- 검증된 암호학적 무결성 보장(메시지 인증 코드, 디지털 서명 등)
- 특정한 암호학적 작업의 수행 → 키 정보 변조 탐지
오류 발생시 키 정보 복원에는 물리적으로 분리, 보관된 키 사본 사용
- 물리적 메커니즘
- 기밀성(confidentiality): 아래 세 가지 조치중 한가지를 사용한다.
- 검증된 알고리즘을 사용한 암호화
- 암호화와 동일한 수준의 물리적 보호 기능
- 접근이 제한된 안전한 보관소에 의해 제공되는 물리적 보호
C. 가용성 보장 기술
1. 비밀 분산 기법(Secret Sharing Scheme, SSS)
사용자의 개인키를 나눈 키 조각(share)을 특정 그룹원에게 분배하는 방법
→ 그룹원들로부터 충분한 키 조각들을 회수했을 때만 복구 가능
- 키 조각은 일정 수 이상의 신뢰할 수 있고 안정적인 참여자들에게 분배
- 키 조각은 참여자의 공개키, 보안 질문, 사용자의 생체정보 등으로 암호화 되어 분배
- 언제든 키 조각을 회수하여 복호화한 뒤 개인키 복구
2. 임계점 사용 메커니즘
참여자 그룹에 대한 공격으로 정상적인 임곗값인 t개의 키 조각을 회수할 수 없는 경우
→ v개(t = 2v)의 키 조각만으로 키 복구 가능
→ 키 조각의 분배에는 공개키 기반 구조(PKI) 등의 중앙형 인증수단 필요
D. 무결성/기밀성 보장 기술 → 패스워드, Keystore
사용자 개인키는 사용자가 설정한 패스워드를 기반으로 Keystore 파일 형태로 암호화되어 존재한다. (UTC/JSON 포맷)
Keystore 파일에 포함된 정보는 다음과 같다.
- 암호화 알고리즘: 암호화에 사용한 알고리즘과 파라미터 정보
→ 주로 양방향 암호화 알고리즘 사용. AES(aes-128-ctr) - 키도출 알고리즘: 사용자 패스워드로부터 개인키 암호화에 사용할 암호화키를 도출하는데 사용한 알고리즘과 파라미터 정보
→ 주로 단방향 알고리즘 사용. Scrypt - 무결성 검증코드(MAC): 개인키 무결성 검증을 위한 메시지 인증코드
→ 암호화된 개인키와 개인키 암호화에 사용된 암호화키 일부에 대한 SHA3-256 해시값
개인키 복호화는 사용자가 입력한 패스워드로부터 재생성한 복호화키와 보관된 개인키의 암호문으로부터 계산한 MAC과 Keystore 파일에 저장된 MAC을 비교하여 두 값이 동일할 때 실시된다.
→ 사용자가 유효한 패스워드를 입력했을 때 패스워드로부터 개인키 복호화를 위한 암호키 획득
→ 획득한 암호키를 사용하여 Keystore 파일 내의 암호화된 개인키 복호화
- cipher: 개인키 암호화에 사용한 알고리즘
- cipherparams: 위 알고리즘에 필요한 변수
- iv(Initialization Vector): 암호화에 필요한 초기값. 16byte(32자리)의 랜덤한 hex 문자열
- ciphertext: 위 알고리즘으로 개인키를 암호화한 결과값
- kdf(Key Derivation Function): 패스워드 암호화에 사용한 알고리즘
- kdfparams: 위 알고리즘에 필요한 변수
- dklen(Derived Key Length): 결과값의 길이
- salt: 암호화에 필요한 솔트 값. 16byte(32자리)의 랜덤한 hex 문자열
- n: CPU/Memory 비용. 클수록 암호화 파워 증가
- r: Block Size. 일반적으로 8 사용
- p: 병렬화 수준. 클수록 암호화 파워 증가
- mac: Keystore 파일 사용시 패스워드 입력값 검증을 위해 사용
E. 지갑 클라이언트 비교
1. 키 저장(가용성)
- 대부분 클라이언트에서 키 복구 솔루션으로 니모닉 코드 사용(BIP-39)
- 일부1 → 신뢰기관이 참여하는 비밀분산기법을 사용하여 키 복구 서비스 제공
- 일부2 → 구글 드라이브 등의 클라우드 서비스와 연계하여 암호화된 시드파일을 외부 저장소에 보관(파일 백업 방식)
2. 키 저장(기밀성/무결성)
- 대부분의 소프트웨어 타입 클라이언트에서 개인키를 암호화 하여 저장소에 보관하고 서명생성 과정에서 사용자가 입력하는 패스워드로 복호화 하여 사용. 패스워드 방식
F. 개인키 관리 가이드라인
- 개인키 암호화 / 복호화 과정
- Keystore 인스턴스 생성, 개인키 임포트 코드 예시
const fs = require('fs');
const { KeyStore } = require('eth-lightwallet');
function createKs() {
const ks = KeyStore.createVault({
password: 'secret',
seedPhrase: '',
hdPathString: "m/44'/60'/0'/0",
});
ks.keyFromPassword('secret', (err, pwDerivedKey) => {
if (err) throw err;
ks.generateNewAddress(pwDerivedKey, 1);
const address = ks.getAddresses()[0];
console.log(address); // 0x20F8D42FB0F667F2E53930fed426f225752453b3
});
}
function importKs() {
const json = fs.readFileSync('./tmp/UTC--2018-07-04T09-58-30.122808598Z--20f8d42fb0f667f2e53930fed426f225752453b3', 'utf8');
KeyStore.deriveKeyFromPassword('secret', (err, pwDerivedKey) => {
if (err) throw err;
const ks = new KeyStore();
ks.importPrivateKey(json, pwDerivedKey, 'secret');
const address = ks.getAddresses()[0];
console.log(address); // 0x20F8D42FB0F667F2E53930fed426f225752453b3
fs.unlinkSync('./tmp/UTC--2018-07-04T09-58-30.122808598Z--20f8d42fb0f667f2e53930fed426f225752453b3');
});
}
createKs();
// importKs();
Reference
[논문] 안전한 블록체인 기반 서비스를 위한 개인키 관리 가이드라인
[블록체인 PICK] 이더리움 KeyStore 파일(UTC) 생성 및 암호화/복호화 원리 #1
[블록체인 PICK] 이더리움 KeyStore 파일(UTC) 생성 및 암호화/복호화 원리 #2