I need to encode a string to UTF-16LE (and convert to sha1 later), but I'm having some problems. This is what I had tried:
let utf16array = Array("password".utf16)
print(utf16array)
// [112, 97, 115, 115, 119, 111, 114, 100]
But this is what I was expecting:
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0]
Same thing using utf8array:
let utf8array = "password".utf8.map({ $0 as UInt8 })
// [112, 97, 115, 115, 119, 111, 114, 100]
So, this is what I did to "fix" it:
var bytesArray:[UInt16] = []
for byte in utf16array {
bytesArray.append(byte)
bytesArray.append(0)
}
print(bytesArray)
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0]
But I'm sure this is not the right way. Any suggestions?
You can get a representation as UTF-16LE data with
let password = "password€"
let data = password.data(using: .utf16LittleEndian)!
print(data as NSData)
// <70006100 73007300 77006f00 72006400 ac20>
That would already be sufficient to compute the SHA1 digest (code from How to crypt string to sha1 with Swift?):
var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA1($0, CC_LONG(data.count), &digest)
}
let hexEncodedDigest = digest.map { String(format: "%02hhx", $0) }.joined()
print(hexEncodedDigest)
// 177f0d080dfe533e102dd67d6321204813cf1b0c
But if you need it as a byte array then
let bytesArray = data.map { $0 }
print(bytesArray)
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0, 172, 32]
would work.
(I have appended a non-ASCII characters for demonstration,
€ = U+20AC
becomes 172, 32
.)
If you are curious how to convert the [UInt16]
array to an
[UInt8]
array, this is how you could do it with some pointer juggling
(and just a single copy):
let utf16array = Array("password€".utf16)
print(utf16array)
// [112, 97, 115, 115, 119, 111, 114, 100, 8364]
let bytes = Array(utf16array.withUnsafeBufferPointer {
$0.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: 2 * utf16array.count) {
UnsafeBufferPointer(start: $0, count: 2 * utf16array.count)
}
})
print(bytes)
// [112, 0, 97, 0, 115, 0, 115, 0, 119, 0, 111, 0, 114, 0, 100, 0, 172, 32]