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

时间:2017-04-12 05:10:06

标签: 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字节数组,以将字符串解码为其原始形式。 / p>

3 个答案:

答案 0 :(得分:22)

您可以将hexa字符串转换回UInt8数组,每两个六进制字符重复一次,并使用UInt8 radix 16初始化程序从中初始化UInt8:

extension StringProtocol {
    var hexaToBytes: [UInt8] {
        let hexa = Array(self)
        return stride(from: 0, to: count, by: 2).compactMap { UInt8(String(hexa[$0...$0.advanced(by: 1)]), radix: 16) }
    }
}

extension Collection where Element == Character {
    var hexaToBytes: [UInt8] {
        var last = first
        return dropFirst().compactMap {
            guard let char = last else {
                last = $0
                return nil
            }
            defer { last = nil }
            return UInt8(String([char,$0]), radix: 16)
        }
    }
}

Swift 5或更高版本

我们可以使用新的Character属性hexDigitValue

extension Collection where Element == Character {
    var hexaToBytes: [UInt8] {
        var last = first
        return dropFirst().compactMap {
            guard
                let lastHexDigitValue = last?.hexDigitValue,
                let hexDigitValue = $0.hexDigitValue else {
                last = $0
                return nil
            }
            defer { last = nil }
            return UInt8(lastHexDigitValue * 16 + hexDigitValue)
        }
    }
}

<强>游乐场:

let hexa = "e0696349774606f1b5602ffa6c2d953f"

let bytes = hexa.hexaToBytes   // [224, 105, 99, 73, 119, 70, 6, 241, 181, 96, 47, 250, 108, 45, 149, 63]

答案 1 :(得分:2)

快速5

import CryptoSwift

let hexString = "e0696349774606f1b5602ffa6c2d953f"
let hexArray = Array<UInt8>.init(hex: hexString) // [224, 105, 99, 73, 119, 70, 6, 241, 181, 96, 47, 250, 108, 45, 149, 63]

答案 2 :(得分:0)

  

基于Leo Dabus的答案

详细信息

  • Swift 5.1,Xcode 11.2.1

解决方案

enum HexConvertError: Error {
    case wrongInputStringLength
    case wrongInputStringCharacters
}

extension StringProtocol {
    func asHexArrayFromNonValidatedSource() -> [UInt8] {
        var startIndex = self.startIndex
        return stride(from: 0, to: count, by: 2).compactMap { _ in
            let endIndex = index(startIndex, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
            defer { startIndex = endIndex }
            return UInt8(self[startIndex..<endIndex], radix: 16)
        }
    }

    func asHexArray() throws -> [UInt8] {
        if count % 2 != 0 { throw HexConvertError.wrongInputStringLength }
        let characterSet = "0123456789ABCDEFabcdef"
        let wrongCharacter = first { return !characterSet.contains($0) }
        if wrongCharacter != nil { throw HexConvertError.wrongInputStringCharacters }
        return asHexArrayFromNonValidatedSource()
    }
}

用法

// Way 1
do {
     print("with validation: \(try input.asHexArray() )")
} catch (let error) {
     print("with validation: \(error)")
}

// Way 2
"12g". asHexArrayFromNonValidatedSource()

完整样本

  

别忘了在此处粘贴解决方案代码

func test(input: String) {
    print("input: \(input)")
    do {
        print("with validation: \(try input.asHexArray() )")
    } catch (let error) {
        print("with validation: \(error)")
    }
    print("without validation \(input.asHexArrayFromNonValidatedSource())\n")
}

test(input: "12wr22")
test(input: "124")
test(input: "12AF")

控制台输出

input: 12wr22
with validation: wrongInputStringCharacters
without validation [18, 34]

input: 124
with validation: wrongInputStringLength
without validation [18, 4]

input: 1240
with validation: [18, 64]
without validation [18, 64]

input: 12AF
with validation: [18, 175]
without validation [18, 175]
相关问题