단방향 암호화
단방향 암호화는 암호화한 데이터를 복호화할 수 없는 암호화 방식. Hash Function를 사용해서 데이터를 해시 값으로 변환.
해시 함수 알고리즘에는 SHA-256, MD5, BCrypt 등 있다.
//java에서는 암호화 메서드(digest)의 입력 파라미터와 리턴 타입이 모두 바이트 계열이다.
byte[] origin = input.getBytes("UTF-8);
MessageDigest digest = MessageDigest.getInstance("SHA-256);
byte[] hash = digest.digest(origin)// byte배열을 암호화
이제 해시를 16진수 표기법이나 Base64표기법 사용해서 문자열로 표현.충돌 저항성(collision resistance)
해시 함수는 원본 데이터에 상관 없이 일정한 길이의 해시값을 생성함. 길이가 제한되기에 서로 다은 데이터가 동일 해시 값 가질 수 있음. 서로 다른 데이터에 대해 최대한 다른 해시 값을 생성하는 해시 알고리즘이 좋다 할 수 있다. 해시 저항성이 크다 .할 수 있는 것
길수록 충돌 가능성 낮으니 SHA 256보다 SHA 512가 더 길어서 충돌 가능성이 낮음.
단항향 암호회는 원본 데이터로 복호화 못해서 비밀번호 찾기 기능 못함. 대신 임의 문자열로 초기화 하고, 사용자는 등록된 이메일같은걸로 초기화된 비번으로 로그인하게 유도하면 됨.
솔트 같은 원본 데이터에 항상 동일한 해시 값을 생성하는건 보안에 취약. 이를 방지하기 위해 솔트를 사용. 솔트는 임의 값이며, 암호화 할때 솔트를 함께 사용하면 솔트 값에따라 원본데이터가 같더라도 해시 값이 다르다.
양방향 암호화
양방향 암호화는 암호화와 복호화 모두 가능한 방식. 서버에 접속시 사용하는 SSH Protocol, API 호출 시 사용하는 HTTPS 처럼 보안이 중요한 데이터 송수진 과정에서 주로 사용.
대표적 알고리즘으로 AED, RSA
양방향 암호화는 암호화, 복호화시 키를 사용.
이 키는 대칭 키 방식, 비대칭 키 방식으로 나뉜다.
대칭 키는 암호화, 복호화시 같은 키를 쓴다. 즉, 암호화와 복호화를 수행하는 쌍이 같은 키를 공유해야한다. 이 방식에서는 키가 유출되면 누구나 암호화된 데이터를 복호화할 수 있기에 키의 보안이 매우 중요.
비대칭 키 암호화는 암호화와 복호화에 서로 다른 키를 쓴다. 공개 키와 개인 키를 생성한다. 공개 키는 누구에게나 공개 할 수 있는 키고 개인 키는 키 소유자만 접근할 수 있어야한다.
공개 키는 데이터를 암호화할 때 사용되며, 개인 키는 암호화된 데이터를 복호화할 때 사용된다.
키 소유자는 공개 키와 개인 키 쌍을 생성 뒤, 데이터 송신자에게 공개 키를 제공함. 공개키로 암호화한건 개인 키로만 복호화되어서 공개키가 유출되어서 노상관.
개인 키로 암호화하고 공개 키로 복호화하는 방식도 있다. 보통 이건 신원 확인이나 서명과 같은 인증 목적으로 사용됨. 개인 키를 사용해서 인증을 수행하는예로 SSH. SSH 서버는 개인 키를 이용한 인증 수단 제공한. SSH 서버에 공개 키 등록하고, 클라는 서버에 접속할 때 개인키를 이용해서 인증함.
SSH의 키 쌍을 이용한 사용자 인증 과정
- 클라는 인증에 쓸 키 쌍의 ID를 서버에 전송.
- 서버는 키 ID에 해당하는 공개 키를 authorized_keys 파일에서 찾는다.
- 공개 키가 존재하면 임의 숫자 생성해 공개 키로 암호화.
- 암호화한 숫자를 클라에 전송.
- 클라는 개인 키로 암호화된 숫자를 복호화.
- 클라는 복호화된 숫자와 공유 세션 키 결합한 값의 해시 구함.
- 클라는 해시 값을 서버에 전송.
- 서버는 클라가 전송한 해시 값과 서버가 임의 숫자와 세션키로 생성한 해시 값이 같은지 비교.
- 두 값이 일치하면 클라를 인증.
AES 대칭 키 암호화 예
다음과 같은 두 값 생성해 공유한다.
- 키
- IV(Initialization Vertor) AES는 키 값으로 128비트, 192비트, 256비트 중 하나를 씀. 바이트로는 각각 16바이트, 24바이트, 32바이트.
생성한 키는 바이너리 파일이나 문자열 형식으로 변환하여 공유하고 보관. 보관된 키를 이용해 암호화를 하려면, 해당 키 데이터로부터 SecretKey 객체를 만들어야됨. 다음은 바이트 배열로 부터 SecretKey를 생성하는 코드.
SecretKey key = new SecretKey(bytes, "AES");
같은 키를 사용해서 같은 데이터를 암호화 하면 항상 같은 결과 생성. 이처럼 반복되는건 보안 취약. 패턴 노출 가능하기에 IV(초기화 벡터)를 쓴다. 패턴 노출을 막을 수 있음.
IV는 임의의 바이트 배열, 암호화시 함께 사용되면 같은 키 쓰더라도 결과 같이 매번 달라 패턴 노출 방지됨. 복호화시 키와 함께 IV도 필요해서 안전히 전달, 보관해야함.
AES는 길이가 16인 바이트 배열을 IV로 사용.
비대칭 키 암호화 예
공개 키/개인 키 쌍 생성후 공개 키를 공유. RSA알고리즘.
공개 키는 바이트 배열을 Base64 형식으로 인코딩하여 문자열로 공유하거나, 바이트 배열 자체를 파일로 저장하여 공유. 개인 키도 유사하게 Base64로 인코딩한 문자열을 저장하거나 바이트배열 자체를 바이너리 형식으로 저장함.
문자열이나 바이너리 형태로 저장한 공개 키, 개인 키는 다시 코드에서 사용가능한 형태로 변환해야함.