2023. 6. 14. 10:58, 공부/iOS
최초 작성: 2023.06.14
ㅇㅇ 가능함.
공개 키 암호화로 공유 비밀 만들고, 그걸로 대칭 키 만들면 데이터 암호화도 되고 데이터 무결성도 보여줄 수 있음. 서버에 공개 키 올려두고 사용하면 된다.
끗.
.
.
.
.
.
어케 하는지 모르겠다고?
ㅇㅋㅇㅋ 레츄고.
📌 CryptoKit 시리즈
1. 암호화 작업을 위한 Apple CryptoKit 알아보기
2. Apple CryptoKit으로 채팅 메세지를 암호화할 수 있을까? (현재 글)
1. CryptoKit으로 메세지 안전하게 송수신하기
이론편
프로젝트에 적용하기 전에 어떤 암호화 방식을 사용할지와 그 이유, 전체 코드 흐름을 살펴보도록 하자.
목적
채팅 메세지를 안전하게 송수신한다. 즉, 채팅 내역은 수신자와 송신자만 볼 수 있어야 한다. 서버에 저장된 채팅은 모두 암호화되며 개발자가 임의로 혹은 실수로 채팅 내용을 알아낼 수 없게 한다.
암호화 방식
공개 키 암호화 + 대칭 키(CryptoKit Curve25519.KeyAgreement + Symmetric Key)
해당 방식을 선택한 이유
메세지를 암호화해서 보내고, 받을 때는 복호화한다. 암호화/복호화를 위한 비밀 키는 메세지를 주고 받는 유저끼리 알고 있어야 한다. 대칭 키를 사용하면 이를 해결할 수 있다. 그러나 문제는 '어떻게 대칭 키를 안전하게 전송할 것이냐' 이다. 그래서 공개 키 암호화로 대칭 키를 만들어 대칭 키를 직접 보내지 않고도 사용할 수 있는 방식을 채택했다.
시나리오
- 사용자 계정 생성 시
- 사용자의 계정을 생성한다.
- 사용자의 Public, Private key를 생성한다.
- Public key는 사용자의 계정 정보(서버)에 저장하고, Private key는 사용자의 기기(keychain 혹은 secure enclave)에 저장한다.
- 사용자 A와 B가 채팅을 할 때
- A, B의 채팅방이 개설된다. (혹은 이미 개설되어 있거나)
- A가 B에게 메세지를 보낸다.
- A의 메세지는 암호화되어 서버에 전송된다.
- B에게 암호화된 메세지가 전달된다.
- 전달된 메세지는 복호화되어 B에게 읽힌다.
전체 코드
import SwiftUI
import CryptoKit
// MARK: 0. Message를 보낼 떄 사용하는 salt 값은 앱의 상수 파일에 선언해두기
let messageSalt = "Message 암호화".data(using: .utf8)!
// MARK: 1. 유저 생성시 Public, Private key 생성하기(KeyAgreement)
let minsuPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let minsuPublicKeyData = minsuPrivateKey.publicKey.rawRepresentation
let jennyPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let jennyPublicKeyData = jennyPrivateKey.publicKey.rawRepresentation
let poongPrivateKey = Curve25519.KeyAgreement.PrivateKey()
let poongPublicKeyData = poongPrivateKey.publicKey.rawRepresentation
// MARK: 2. message 송신 (minsu -> jenny)
// 2-1. message 내용
let messageContent = "제니야 안녕? 나 민수야."
// 2-2. 대칭 키 생성
let jennyPublicKey = try! Curve25519.KeyAgreement.PublicKey(rawRepresentation: jennyPublicKeyData)
let MSsharedSecret = try! minsuPrivateKey.sharedSecretFromKeyAgreement(with: jennyPublicKey)
let MSsymmetricKey = MSsharedSecret.hkdfDerivedSymmetricKey(
using: SHA256.self,
salt: messageSalt,
sharedInfo: Data(),
outputByteCount: 32
)
// 2-3. message 암호화
let messageContentData = messageContent.data(using: .utf8)!
let encryptedMessageData = try! ChaChaPoly.seal(messageContentData, using: MSsymmetricKey).combined
let minsuSealedBox = try! ChaChaPoly.SealedBox(combined: encryptedMessageData)
// 2-4. message 송신
/// [sealedBox]를 서버에 올린다.
// MARK: 3. message 수신 (jenny <- minsu)
// 3-1. message 수신
/// minsuSealedBox를 받았다.
// 3-1. 대칭 키 생성
let minsuPublicKey = try! Curve25519.KeyAgreement.PublicKey(rawRepresentation: minsuPublicKeyData)
let JEsharedSecret = try! jennyPrivateKey.sharedSecretFromKeyAgreement(with: minsuPublicKey)
let JEsymmetricKey = JEsharedSecret.hkdfDerivedSymmetricKey(
using: SHA256.self,
salt: messageSalt,
sharedInfo: Data(),
outputByteCount: 32
)
// 3-2. message 복호화
let decryptedMessageData = try! ChaChaPoly.open(minsuSealedBox, using: JEsymmetricKey)
String(decoding: decryptedMessageData, as: UTF8.self)
2. SwiftUI로 Demo 프로젝트 만들기
실전편
- 개발 상황 가정: firebase를 사용하여 채팅 내역 저장, firebase의 firestore + listener로 실시간 채팅 기능 구현
(준비중)
'공부 > iOS' 카테고리의 다른 글
암호화 작업을 위한 Apple CryptoKit 알아보기 (2) | 2023.06.12 |
---|---|
[SwiftUI] Firebase의 GitHub 로그인으로 Auto Login 구현하기 (0) | 2023.06.12 |
[SwiftUI] 네? iOS15에는 sheet의 크기를 조절할 수 없다구요? 그럼 직접 만들지 뭐... (2) | 2023.05.07 |
[SwiftUI] SwiftUI에서 무한스크롤(Infinite Scroll) 구현하기 (0) | 2023.05.07 |
Comments, Trackbacks