78 lines
2.4 KiB
Swift
78 lines
2.4 KiB
Swift
//
|
||
// 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
|
||
}
|
||
}
|
||
|
||
}
|