해당 포스팅은 MVVM패턴 + RxSwift로 이루어진 예제입니다.
안녕하세요 욱승임당
이번 포스팅에서는 라이브러리를 통한 암복호화를 해볼건데요
앱에서 따로 암복호화 알고리즘을 구현하지 않고 라이브러리를 사용해서 간단히 암복화를 할 수 있다고 하더라구여
이 라이브러리도 뱅크샐러드에서 사용중이라고 합니다!
그럼 가보쟈고
카카오 떡상 가즈아!!!
GitHub
Podfile
pod 'CryptoSwift' # Swfit 로 작성된 cryptographic algorithms들을 모아둔 라이브러리
import
import CryptoSwift
AES 알고리즘을 활용한 코드로 구현해볼껀데 그전에 알고리즘의 장단점을 알고 구현하면 더 좋겠쥬?😉
AES(Advanced Encryption Standard)는 현재 가장 널리 사용되는 대칭키 암호화 알고리즘 중 하나입니다. AES의 장점과 단점은 다음과 같습니다:
장점:
- 보안성: AES는 안전하고 강력한 암호화 알고리즘으로 알려져 있습니다. 적절한 키 길이를 사용하고 올바른 모드와 패딩을 적용하면 매우 안전한 암호화를 제공합니다.
- 효율성: AES는 암호화 및 복호화 과정에서 빠르고 효율적입니다. 최신 하드웨어와 소프트웨어 최적화 기술을 활용하면 더욱 빠른 처리가 가능합니다.
- 널리 지원: AES는 전 세계적으로 표준화되어 있으며, 다양한 플랫폼과 프로그래밍 언어에서 지원됩니다. 이는 상호 운용성을 높여줍니다.
단점:
- 대칭키 알고리즘: AES는 대칭키 알고리즘으로, 암호화와 복호화에 동일한 키를 사용합니다. 이는 키 분배와 관리에 대한 문제를 야기할 수 있습니다. 안전한 키 교환 및 보안 키 저장소의 필요성이 있습니다.
- 공격에 대한 취약성: AES 자체는 매우 강력하지만, 구현 방식, 키 관리, 취약한 애플리케이션 설계 등의 요소에 따라 공격에 취약할 수 있습니다. 잘못된 구현이나 암호 분석 기법에 의해 공격될 수 있으므로 주의가 필요합니다.
- 사회적 공격: AES는 암호화와 복호화에 사용되는 키를 외부에 안전하게 보호해야 합니다. 키가 유출되거나 제 3자에게 악용될 경우 암호화된 데이터의 보안이 손상될 수 있습니다.
AES는 현재 암호화 표준으로 널리 사용되고 있으며, 일반적으로 안전하고 효율적인 선택입니다. 그러나 암호화 시스템의 전반적인 보안은 알고리즘 선택 외에도 구현, 키 관리, 보안 프로토콜 등 다양한 요소에 따라 결정되므로 전체 시스템의 보안을 고려해야 합니다.
보아하니 키의 은닉을 강조 하는 것 같죠? '키'값만 안전하게 보관된다면 안전한 알고리즘이다~ 이말이당
키값 보관 가이드라인
암호화 시스템에서 키를 안전하게 보관하는 것은 매우 중요합니다. 키의 안전한 보관을 위해 고려해야 할 몇 가지 가이드라인은 다음과 같습니다:
- 키의 물리적 보안: 키를 물리적으로 안전한 장소에 저장해야 합니다. 안전한 잠금장치가 있는 잠금 보관함이나 금고, 안전한 서버 룸 등의 장소를 사용하는 것이 좋습니다. 또한 접근 권한을 제한하고 키에 대한 로깅 및 감시를 설정하여 불법 접근을 방지해야 합니다.
- 키의 암호화: 키를 저장할 때, 추가적인 보안을 위해 키 자체를 암호화할 수 있습니다. 키를 암호화하려면 다른 암호화 키 또는 암호화 비밀번호가 필요하므로, 암호화 키 또는 비밀번호를 안전하게 관리해야 합니다.
- 키 관리 및 접근 제어: 키에 대한 접근을 엄격히 제어해야 합니다. 적절한 접근 제어 메커니즘과 권한 관리 시스템을 구현하여 키에 접근할 수 있는 사람을 제한하고, 키를 필요로 하는 프로세스나 서비스에만 키를 제공해야 합니다.
- 키 분배: 키를 안전하게 분배해야 합니다. 안전하지 않은 통신 채널을 통해 키를 전송하지 않도록 주의해야 합니다. 안전한 키 교환 프로토콜을 사용하거나, 공개 키 암호화를 활용하여 키를 안전하게 전송할 수 있습니다.
- 키 회전: 일정한 주기로 키를 회전시키는 것이 좋습니다. 키 회전은 키가 유출될 경우의 피해를 최소화하고, 암호 시스템의 보안을 유지하기 위해 중요합니다.
- 안전한 키 저장소 사용: 키를 안전하게 저장하는데 사용되는 키 저장소는 보안 요구 사항을 충족해야 합니다. 예를 들어, iOS 애플리케이션의 경우 Keychain을 사용하여 키를 안전하게 저장할 수 있습니다. 이러한 키 저장소는 키를 암호화하고 안전한 환경에서 보호됩니다.
예제코드
View
import Foundation
import UIKit
import CryptoSwift
import RxSwift
import RxCocoa
final class CryptoViewController: UIViewController, UIViewControllerAttribute {
let disposeBag = DisposeBag()
let viewModel = CryptoViewModel()
var navTitle: String?
let cryptoTextField = UITextField().then {
$0.borderStyle = .roundedRect
}
let cryptoButton = UIButton(type: .system).then {
$0.setTitle("암호화", for: .normal)
}
lazy var originLabel = UILabel().then {
$0.text = "기존 텍스트 :"
$0.textAlignment = .left
$0.numberOfLines = 0
$0.textColor = .black
$0.lineBreakMode = .byCharWrapping
}
lazy var encryptLabel = UILabel().then {
$0.text = "암호화 :"
$0.textAlignment = .left
$0.numberOfLines = 0
$0.textColor = .black
}
lazy var decryptLabel = UILabel().then {
$0.text = "복호화 :"
$0.textAlignment = .left
$0.numberOfLines = 0
$0.textColor = .black
}
override func viewDidLoad() {
super.viewDidLoad()
setNavigationBar()
setUI()
setAttributes()
bindRx()
}
func setNavigationBar() {
self.navigationItem.title = navTitle ?? ""
}
func setUI() {
self.view.backgroundColor = .white
self.view.addSubview(cryptoTextField)
self.view.addSubview(cryptoButton)
self.view.addSubview(encryptLabel)
self.view.addSubview(decryptLabel)
self.view.addSubview(originLabel)
}
func setAttributes() {
cryptoTextField.snp.makeConstraints {
$0.top.equalTo(self.view.safeAreaLayoutGuide).offset(30)
$0.centerX.equalToSuperview()
$0.width.equalTo(350)
$0.height.equalTo(50)
}
cryptoButton.snp.makeConstraints {
$0.top.equalTo(cryptoTextField.snp.bottom).offset(20)
$0.centerX.equalTo(cryptoTextField.snp.centerX)
$0.width.equalTo(200)
$0.height.equalTo(40)
}
originLabel.snp.makeConstraints {
$0.top.equalTo(cryptoButton.snp.bottom).offset(20)
$0.left.equalTo(20)
$0.right.equalTo(-20)
$0.height.equalTo(100)
}
encryptLabel.snp.makeConstraints {
$0.top.equalTo(originLabel.snp.bottom).offset(20)
$0.left.equalTo(20)
$0.right.equalTo(-20)
$0.height.equalTo(originLabel.snp.height)
}
decryptLabel.snp.makeConstraints {
$0.top.equalTo(encryptLabel.snp.bottom).offset(20)
$0.left.equalTo(20)
$0.right.equalTo(-20)
$0.height.equalTo(originLabel.snp.height)
}
}
func bindRx() {
// cryptoBool에 따라 버튼title / textfield isEnable값 변경
viewModel.cryptoBool
.subscribe(onNext: {
self.cryptoTextField.isEnabled = !$0
$0 ? self.cryptoButton.setTitle("복호화", for: .normal) : self.cryptoButton.setTitle("암호화", for: .normal)
})
.disposed(by: disposeBag)
// cryptoTextField TextDidChange
cryptoTextField.rx.text
.orEmpty
.asObservable()
.subscribe(onNext: {
self.originLabel.text = "기존 텍스트 : \($0)"
self.viewModel.inputText.accept($0)
})
.disposed(by: disposeBag)
// cryptoButton 버튼 탭 / 버튼 제목에 따라 함수 분기처리
cryptoButton.rx.tap
.subscribe(onNext: {
let title = self.cryptoButton.titleLabel?.text
title == "암호화" ? self.viewModel.encrypt() : self.viewModel.decrypt()
})
.disposed(by: disposeBag)
// viewModel에서 기존 텍스트에서 암호화된 텍스트 view에 bind
viewModel.encryptedText
.map { "암호화 텍스트 : \($0)" }
.bind(to: encryptLabel.rx.text)
.disposed(by: disposeBag)
// viewModel에서 암호화 텍스트에서 복호화된 텍스트 view에 bind
viewModel.decryptedText
.map { "복호화 텍스트 : \($0)" }
.bind(to: decryptLabel.rx.text)
.disposed(by: disposeBag)
}
}
RxSwift를 통한 비동기식 처리
ViewModel
import Foundation
import RxSwift
import RxCocoa
import CryptoSwift
final class CryptoViewModel {
let inputText = BehaviorRelay<String>(value: "") // 기존 텍스트
let encryptedText = BehaviorRelay<String>(value: "") // 암호화 텍스트
let decryptedText = BehaviorRelay<String>(value: "") // 복호화 텍스트
let cryptoBool = BehaviorRelay<Bool>(value: false) // false => 복호화 or 기존 텍스트 상태 / true => 암호화된 상태
private let encryptionKey = "SecretKey123" // 키값, 해당 키값은 은닉 해야함
/// 암호화
func encrypt() {
guard let input = inputText.value.data(using: .utf8) else {
return
}
do {
let password = Array(encryptionKey.utf8)
let salt = Array("salt".utf8)
let derivedKey = try PKCS5.PBKDF2(password: password, salt: salt).calculate()
let aes = try AES(key: derivedKey, blockMode: ECB(), padding: .pkcs7)
let encrypted = try aes.encrypt(input.bytes)
let encryptedData = Data(encrypted)
let encryptedString = encryptedData.base64EncodedString()
encryptedText.accept(encryptedString)
cryptoBool.accept(true)
} catch {
print("Encryption error: \(error)")
}
}
/// 복호화
func decrypt() {
guard let input = Data(base64Encoded: encryptedText.value) else {
return
}
do {
let password = Array(encryptionKey.utf8)
let salt = Array("salt".utf8)
let derivedKey = try PKCS5.PBKDF2(password: password, salt: salt).calculate()
let aes = try AES(key: derivedKey, blockMode: ECB(), padding: .pkcs7)
let decrypted = try aes.decrypt(input.bytes)
let decryptedData = Data(decrypted)
if let decryptedString = String(data: decryptedData, encoding: .utf8) {
decryptedText.accept(decryptedString)
cryptoBool.accept(false)
}
} catch {
print("Decryption error: \(error)")
}
}
}
결과
테스트 해보니 이모티콘도 같이 암호화 됨 ,, 😂
결론
개인정보 보호법이 강조되고 있는만큼 데이터 암호화도 같이 강조되고 있다. 유용한 라이브러리 같으니 알아두자 ㅎㅎ
'iOS > Library' 카테고리의 다른 글
[iOS] Firebase Crashlytics 설정 (0) | 2024.08.13 |
---|---|
[Swift] Atributika, HTML 코드를 Swift 코드에 녹이기 (0) | 2023.05.26 |
[Swift] 구글 AdMob, 앱에 광고달기 (0) | 2023.03.15 |
[iOS] CocoaPods could not find compatible versions for pod (0) | 2023.03.14 |
[Swift] Toast메시지 띄우기 (0) | 2023.03.10 |