// // NonceGenerator.swift // punchnet // // Created by 安礼成 on 2026/3/17. // import Foundation import CryptoKit /// ChaCha20-Poly1305 加解密示例 struct CCChaCha20Cipher: CCDataCipher { private let key: SymmetricKey private let nonceGenerator: NonceGenerator init(regionId: UInt32, keyData: Data) { self.key = SymmetricKey(data: keyData) self.nonceGenerator = NonceGenerator(regionId: regionId) } /// 加密 func encrypt(plainText: Data) throws -> Data { let nonce = nonceGenerator.nextNonceData() let sealedBox = try ChaChaPoly.seal(plainText, using: key, nonce: .init(data: nonce)) return sealedBox.combined } /// 解密 func decrypt(cipherText: Data) throws -> Data { let sealedBox = try ChaChaPoly.SealedBox(combined: cipherText) return try ChaChaPoly.open(sealedBox, using: key) } } extension CCChaCha20Cipher { /// Nonce生成器(基于ServerRange + 毫秒时间低位 + 本地自增counter) final class NonceGenerator { private let locker = NSLock() private let regionId: UInt32 // 32-bit 全局前缀 private var counter: UInt64 = 0 // 自增counter init(regionId: UInt32) { self.regionId = regionId } /// 生成64-bit Nonce func nextNonceData() -> Data { locker.lock() defer { locker.unlock() } let nowMillis = UInt64(Date().timeIntervalSince1970 * 1000) // 时间占用40个bit位, 自增id占用24位 let timeMask: UInt64 = (1 << 40) - 1 let timeLow = nowMillis & timeMask // 生成 Nonce let counterMask: UInt64 = (1 << 24) - 1 let nonce = (timeLow << 24) | (counter & counterMask) // 自增counter self.counter = (self.counter + 1) & counterMask // 超过最大值回到0 var data = Data() // region: UInt32 -> 4字节大端 data.append(contentsOf: withUnsafeBytes(of: regionId.bigEndian, Array.init)) // nonce: UInt64 -> 8字节大端 data.append(contentsOf: withUnsafeBytes(of: nonce.bigEndian, Array.init)) return data } } }