ios - 如何在 Swift 中将十六进制字符串转换为 UInt8 字节数组?

标签 ios swift encryption aes

我有以下代码:

var encryptedByteArray: Array<UInt8>?
do {
    let aes = try AES(key: "passwordpassword", iv: "drowssapdrowssap")
    encryptedByteArray = try aes.encrypt(Array("ThisIsAnExample".utf8))
} catch {
    fatalError("Failed to initiate aes!")
}

print(encryptedByteArray!) // Prints [224, 105, 99, 73, 119, 70, 6, 241, 181, 96, 47, 250, 108, 45, 149, 63]

let hexString = encryptedByteArray?.toHexString()

print(hexString!) // Prints e0696349774606f1b5602ffa6c2d953f

如何将 hexString 转换回相同的 UInt8 字节数组?

我问的原因是因为我想通过加密的十六进制字符串与服务器通信,我需要将其转换回 UInt8 字节数组以将字符串解码为其原始字符串形式。

最佳答案

您可以将六边形 String 转换回 [UInt8] 数组,每两个六边形字符迭代一次,并使用其字符串基数初始化一个 UInt8初始值设定项。以下实现假设六边形字符串格式正确:


编辑/更新:Xcode 11 • Swift 5.1

extension StringProtocol {
    var hexaData: Data { .init(hexa) }
    var hexaBytes: [UInt8] { .init(hexa) }
    private var hexa: UnfoldSequence<UInt8, Index> {
        sequence(state: startIndex) { startIndex in
            guard startIndex < self.endIndex else { return nil }
            let endIndex = self.index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
            defer { startIndex = endIndex }
            return UInt8(self[startIndex..<endIndex], radix: 16)
        }
    }
}

let string = "e0696349774606f1b5602ffa6c2d953f"
let data = string.hexaData    // 16 bytes
let bytes = string.hexaBytes  // [224, 105, 99, 73, 119, 70, 6, 241, 181, 96, 47, 250, 108, 45, 149, 63]

如果你也想处理格式错误的六边形字符串,你可以把它变成一个抛出方法:

extension String {
    enum DecodingError: Error {
        case invalidHexaCharacter(Character), oddNumberOfCharacters
    }
}

extension Collection {
    func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
        sequence(state: startIndex) { lowerBound in
            guard lowerBound < endIndex else { return nil }
            let upperBound = index(lowerBound,
                offsetBy: maxLength,
                limitedBy: endIndex
            ) ?? endIndex
            defer { lowerBound = upperBound }
            return self[lowerBound..<upperBound]
        }
    }
}

extension StringProtocol {
    func hexa<D>() throws -> D where D: DataProtocol & RangeReplaceableCollection {
        try .init(self)
    }
}

extension DataProtocol where Self: RangeReplaceableCollection {
    init<S: StringProtocol>(_ hexa: S) throws {
        guard hexa.count.isMultiple(of: 2) else {
            throw String.DecodingError.oddNumberOfCharacters
        }
        self = .init()
        reserveCapacity(hexa.utf8.count/2)
        for pair in hexa.unfoldSubSequences(limitedTo: 2) {
            guard let byte = UInt8(pair, radix: 16) else {
                for character in pair where !character.isHexDigit {
                    throw String.DecodingError.invalidHexaCharacter(character)
                }
                continue
            }
            append(byte)
        }
    }
}

用法:

let hexaString = "e0696349774606f1b5602ffa6c2d953f"
do {
    let bytes: [UInt8] = try hexaString.hexa()
    print(bytes)
    let data: Data = try hexaString.hexa()
    print(data)
} catch {
    print(error)
}

这将打印

[224, 105, 99, 73, 119, 70, 6, 241, 181, 96, 47, 250, 108, 45, 149, 63]
16 bytes

关于ios - 如何在 Swift 中将十六进制字符串转换为 UInt8 字节数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43360747/

相关文章:

iPad HTML5 全屏 Web 应用程序上的 Javascript 缓存

ios8 : Plain label font gets mixed up when replacing text

ios - Azure Pipelines 工作陷入构建 iOS 版本的 React Native 应用程序的困境

ios - 在 Swift 4 的搜索栏中搜索超过 2 个单词时应用程序崩溃

ios - 返回 uicolors 数组的类别

ios - 渐变不填满所有的UIView

ios - `willPresent notification` 是 't called & local notifications aren' t 当应用程序在 iOS 10 中处于前台时不显示

encryption - 建议用于存储密码的哈希算法是什么?

c - 了解 NSS PK11_CipherOp 和 C 内存分配

mysql - 跟踪数据访问