티스토리 뷰

안녕하세요.

이번엔 이론적인 내용을 이야기 해볼까 합니다. 

 

* 해당 포스트는 CryptoKit 을 사용합니다. (iOS 13.0 이상만 가능)

 

보안 회사에서 일할때 소금? 이야기를 많이 들었는데 

오늘은 이게 뭔지 그리고 어떤 느낌으로 사용되는지 까지 해보도록 하겠습니다. 

 

* 그래서 소금(Salt)이 뭔가요?

- 보안에서 말하는 소금이란 사용자가 자신의 데이터를 Hash로 만들기 전에 데이터를 들키지 않게 하기 위해 넣는 임의의 데이터를 의미합니다. 

- Hash는 단방향 암호화 (복호화가 불가능한 데이터)이지만 같은데이터로 Hash값를 제작하면 같은 Hash 값이 나오게 되기때문에 이를 통해 원본 데이터를 유츄해보는 것은 이론적으로 가능합니다.

- 그래서 유추할수없도록 가짜 데이터를 추가하는것이라고 합니다. (보통 사용자마다 다른 소금을 사용한다고 합니다.)

이런 느낌입니다.

* 번외 후추(Pepper)는 뭔가요?

- 소금이 사용자마다 다른 소금이라면 후추는 서버(관리자)만이 사용할수있는 특별 비밀 데이터입니다.(주방장의 비밀레시피?)

- 후추를 통해 사용자의 데이터를 서버에서 더 안전하게 저장하기 위해 사용되며 사용자마다 동일한 후추를 사용한다고 합니다.

- 후추는 소금과 달리 유출되면 여러 사람의 데이터가 위험하기 때문에 굉장히 안전한 장소에만 보관되고 소금처럼 개인 단위로 저장하지 않는다고 합니다. 

 

결국 비슷한데 사용자마다 다르냐 같냐의 차이로 소금과 후추로 나뉘는 것 같네요.

 

아무튼 이걸 하려던게 아니라 

그래서 이걸 어떻게 구현하는지 알아봅시다. 

 

생각보다 간단한데 

  1. 내가 사용할 소금 만들기 
  2. 내 데이터에 소금 합치기 
  3. 그걸로 Hash 만들기 

이제 swift 에서 제공되는 친구들로 한단계씩 만들어봅시다.

 

1. 내가 사용할 소금 만들기

- 놀랍게도 좋은 함수를 제공해주고 있습니다. 

- SecRandomCopyBytes 를 사용해서 소금을 만들어봅시다. 

let saltLength = 16 // 소금 길이
var saltData = Data(count: saltLength) // 소금을 만들어 담을 공간 생성
// 빈 소금통이 잘 만들어졌는지 확인
print("Empty Salt Data : \(saltData.base64EncodedString())")
// 소금통 채우기 (랜덤값 채우기)
let makeSaltResult = saltData.withUnsafeMutableBytes{bytes in
    SecRandomCopyBytes(kSecRandomDefault, saltLength, bytes.baseAddress!)
}
// 랜덤값이 잘 들어갔는지 확인
if makeSaltResult == errSecSuccess{// 잘 만들어졌는지
	// 소금 값 확인 
    print("Salt Data : \(saltData.base64EncodedString())")
}

- 함수 이름이 길어 보이는 것 뿐 사실 내용을 따지면 별로 어렵지 않습니다. 

- 소금을 넣을 통을 만들고 소금을 랜덤으로 만든다 이 의미입니다.  

 

2. 내 데이터에 소금 합치기 

- 저는 모두의 예시인 "Hello world"를 이용해보겠습니다. 

- swift 에서는 복잡하게 할 필요없이 이런 식으로 합치는게 가능합니다. 

let myData = "Hello world".data(using: .utf8)!
let mySecretData : Data = myData+saltData // 내 데이터와 소금 합치기

 

3. 그걸로 Hash 만들기 

- CryptoKit 함수를 불러와야하기때문에 코드 맨위에 아래 한줄을 먼저 추가해줍니다. 

import CryptoKit // Apple에서 제공해주는 친구입니다.

- 이 친구가 Hash 를 만드는 함수를 제공해주는데 저는 SHA256으로 만들어보겠습니다. 

func makeHash(data:Data) -> SHA256Digest{
    return SHA256.hash(data: data) // 데이터 해쉬값 만들기
}

- 보면 리턴 값이 굉장히 특이한데 이게 Apple 측 설명을 보면 아래처럼 되어있습니다. 

리턴 타입인데 SHA256전용? 그런 느낌입니다

- 아무튼 그래서 이걸 서버에 보내든 저희가 스트링으로 확인을 하든 그래야하는데 저 타입이면 곤란하기 때문에 바꿔봅시다.

- 참고로 그냥 .description 하면 결과가 아래처럼 나옵니다. 

앞에 SHA256 digest만 빼면 저희가 원하는 값이긴 합니다.

- 이거 말고 이렇게 뜨는게 있는데 이걸로 한번 만들어봅시다. 

자동완성이 좋네요

print(makeHash(data:mySecretData).compactMap { String(format: "%02x", $0) }.joined())

- 이러면 이제 SHA256 digest 가 붙어 있지 않은 상태로 원본 값이 String 으로 나오게 됩니다. 

이걸 서버에 보내거나 하면 되겠죠?

소금이 매번 달라지기 때문에 

매번 Hash 함수를 통해 나오는 값이 달라지는 걸 알 수 있습니다.

 

오늘은 개인적으로 궁금했던 부분을 이론적으로 공부하고

Apple의 CryptoKit 을 통해 간단히 구현을 해봤습니다. 

글이 많이 부족하긴 하지만 

저처럼 이 부분에 대해 궁금하실 분들을 위해 한번 올려봅니다. 

누군가에게 도움이 되었으면 좋겠네요.

 

오늘도 파이팅입니다. 

 

댓글