iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0

https://ithelp.ithome.com.tw/upload/images/20231012/20130138mTJXXKOosK.jpg
Photo by Sébastien Goldberg on Unsplash
Mount Cook, New Zealand
生活情境:當你身處在外商工作,周遭同事都是英文溝通,新來同事,在茶水間相遇,意外發現新同事會講台語,從此你跟新同事在茶水間透過台語加密講八卦,這就是加密解密☕️

打 API 時,怕有心人士竊取資料,可以替你 API 加密、加鹽(Salt)、initialization vector。

資安防護人人有責 💪🏻

https://github.com/krzyzanowskim/CryptoSwift

Swift Package Manager

.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.8.0"))
import CryptoSwift

反正我從這 stackoverflow 改成我要的需求

Transform Java AES Decryption Code to CryptoSwift

extension String {

// 加密方法
func encrypt(key: String, value: String) -> String {
    // 初始化一個空的結果字符串
    var result = ""
    do {
        // 將 key 和 value 轉換為字節數組
        let key: [UInt8] = Array(key.utf8)
        let value: [UInt8] = Array(value.utf8)
        
        // 創建 AES 加密器,使用 CBC 模式和 pkcs7 填充
        let aes = try! AES(key: key, blockMode: CBC(iv: value), padding: .pkcs7)
        
        // 加密當前字符串
        let encrypted = try aes.encrypt(Array(self.utf8))
        
        // 將加密後的字節數組轉換為 Base64 格式的字符串
        result = encrypted.toBase64() ?? ""
    } catch {
        // 如果有錯誤,則打印錯誤
        print("Error: \(error)")
    }
    return result
}

// 解密方法
func decrypt(key: String, value: String) -> String {
    // 初始化一個空的結果字符串
    var result = ""
    do {
        // 從當前字符串獲取加密的內容
        let encrypted = self
        
        // 將 key 和 value 轉換為字節數組
        let key: [UInt8] = Array(key.utf8)
        let value: [UInt8] = Array(value.utf8)
        
        // 創建 AES 解密器,使用 CBC 模式和 pkcs7 填充
        let aes = try! AES(key: key, blockMode: CBC(iv: value), padding: .pkcs7)
        
        // 解密加密的內容
        let decrypted = try aes.decrypt(Array(base64: encrypted))
        
        // 將解密後的字節數組轉換為字符串
        result = String(data: Data(decrypted), encoding: .utf8) ?? ""
    } catch {
        // 如果有錯誤,則打印錯誤
        print("Error: \(error)")
    }
    return result
}
}

使用派生鍵 (derived key) 是對密鑰的一種強化方法,通常使用密碼基於鍵的 key derivation function (KDF)。PBKDF2 (Password-Based Key Derivation Function 2) 是其中一個常用的 KDF。

以下是如何使用 Swift 來生成一個派生鍵的例子,這裡使用了 CommonCrypto 庫來實現 PBKDF2:

  1. 首先,確保你的 Swift 專案已經包含了 CommonCrypto 這個模塊。
  2. 使用以下的方法來生成派生鍵:
import CommonCrypto

func derivedKey(password: String, salt: Data, iterations: Int, keyLength: Int) -> Data? {
    var derivedKeyData = Data(count: keyLength)

    let derivationStatus = derivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
        salt.withUnsafeBytes { saltBytes in
            CCKeyDerivationPBKDF(
                CCPBKDFAlgorithm(kCCPBKDF2),
                password,
                password.count,
                saltBytes.baseAddress,
                salt.count,
                CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA256),
                UInt32(iterations),
                derivedKeyBytes.baseAddress,
                keyLength
            )
        }
    }

    return derivationStatus == kCCSuccess ? derivedKeyData : nil
}

  1. 使用此方法生成派生鍵:
let password = "yourPasswordHere"
let salt = "someRandomSalt".data(using: .utf8)!
let iterations = 10000 // 推薦至少使用 10,000 次迭代
let desiredKeyLength = 32 // 例如,對於 256 位的 AES 鍵

if let derivedKey = derivedKey(password: password, salt: salt, iterations: iterations, keyLength: desiredKeyLength) {
    print("Derived Key: \\(derivedKey.base64EncodedString())")
}

請注意,為了提高安全性,應該使用隨機生成的鹽,而不是硬編碼的鹽。而且,迭代次數也應該根據需要進行調整,但總體上,使用更多的迭代次數會增加密鑰派生的計算難度,從而增加安全性。


Tips: 跟後端確認 iterations 是多少,有些語言 iterations 沒設定是 default 某值,解密老半天,才發現前端跟後端 iterations 參數不一樣


Tips: 解密由於會花時間,會有時間差記得要 DispatchGroup 管理多個異步操作。


什么是加密? - 密码、摘要、盐和 IV 指南 | HackerNoon

初始向量 - 維基百科,自由的百科全書


上一篇
Day 27: MVVM傳值,不是傳情
下一篇
Day 29: Azure Active Directory
系列文
SwiftUI 男孩30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言