PIN Block Calculation in Swift - ios

how to implement this steps in swift
Get the encrypted TWK in this format e077b34665f66eb5.
Get clear TWK by decrypt TWK using the stored TMK when TMK is abcdef0123456789 using DES as decryption method.
Prepare PIN block using ANSI X9.8 (ISO Format 0) format as follows:
Calculate P1: [0][pin_length][pin] then right padded with 'F's, example for PIN = "0000", P1:"040000FFFFFFFFFF"
Calculate P2: Get account from PAN by taking the last 12 digits of the PAN not including the Luhn code and left padded with zeros, example for PAN = "1234567890123456", P2:"0000456789012345"
clear PIN Block = p1 XOR p2, for above P1 and P2 = 0400459876fedcba
Encrypt the PIN block using the clear TWK key and DES as encryption method.
ii try to do it with CommonCrypto
class Handeller{
var pinBlock:String = "";
func Handeller(tmk:String , workingKey:String ,pan:String ,pin:String){
var p1:String = ""
var p2:String = ""
p1.append("0")
p1.append(String(pin.count))
p1.append(pin)
var i:Int = 0
for i in 0...15-p1.count{
p1.append("F")
}
p2.append("0000")
var y:Int = 0
for i in 0...11{
let panChar = pan.characters.map { (Character) -> Character in
return Character
}
p2.append(panChar[pan.count-13+i])
}
print(p1)
print(p2)
// to get clear workingKey
print(myDecrypt(mykey: tmk, myString: workingKey))
let text = [UInt8](p1.utf8)
let cipher = [UInt8](p2.utf8)
var encrypted = [UInt8]()
print("text \(text)")
// encrypt bytes
//for t in enumerate(text) {
for (index, t) in text.enumerated(){
encrypted.append(t ^ cipher[index])
}
var str = String(bytes: encrypted, encoding: String.Encoding.utf8)
print(str)
for (index, t) in encrypted.enumerated(){
print(t)
}
print("\\\\\\\\\\\\\\\\\\\\\\\\\\")
for (index, t) in encrypted.enumerated(){
print(String(t, radix: 16))
}
String(bytes: encrypted, encoding: String.Encoding.utf8)
print(toByteArray(String(bytes: encrypted, encoding: String.Encoding.utf8)!))
}
func myDecrypt (mykey:String , myString:String) -> String{
//let tmkByte = String(mykey).utf8.map{ UInt8($0) }
print("key is \(mykey)")
print("data is \(myString)")
if
let key = mykey.data(using: .utf8),
let data = myString.data(using: .utf8)
//let data = Data(Hex: myString, options: .ignoreUnknownCharacters) //<-#1
{
print("key byte num is \(key)")
print("data byte num is \(data)")
var numBytesDecrypted: size_t = 0
var result = Data(count: data.count) //<-#2
print("result length \(result)")
let err = result.withUnsafeMutableBytes {resultBytes in
data.withUnsafeBytes {dataBytes in
key.withUnsafeBytes {keyBytes in
CCCrypt(CCOperation(kCCDecrypt), CCAlgorithm(kCCAlgorithmDES), CCOptions(kCCOptionPKCS7Padding|kCCModeECB), keyBytes, kCCKeySizeDES, nil, dataBytes, data.count, resultBytes, result.count, &numBytesDecrypted) //<-#4
}
}
}
if err != CCCryptorStatus(kCCSuccess) {
NSLog("Decryption failed! Error: \(err.description)")
}
print(numBytesDecrypted)
result.count = numBytesDecrypted //<-#3
print(result as NSData) //`as NSData` is good for debugging.
//let NSDATA = result as NSData
//init?(data: Data, encoding: String.Encoding)
//print ("string is \(result.hexEncodedString())")
return String(data: result , encoding: .utf8) ?? "???1"
//return result.hexEncodedString()
}
return "???2"
}
func toByteArray( _ hex:String ) -> [UInt8] {
// remove "-" from Hexadecimal
var hexString = hex.removeWord( "-" )
let size = hexString.characters.count / 2
var result:[UInt8] = [UInt8]( repeating: 0, count: size ) // array with length = size
// for ( int i = 0; i < hexString.length; i += 2 )
for i in stride( from: 0, to: hexString.characters.count, by: 2 ) {
let subHexStr = hexString.subString( i, length: 2 )
result[ i / 2 ] = UInt8( subHexStr, radix: 16 )! // ! - because could be null
}
return result
}}
extension Data {
func hexEncodedString() -> String {
return map { String(format: "%02hhx", $0) }.joined()
}}
extension String {
func subString( _ from: Int, length: Int ) -> String {
let size = self.characters.count
let to = length + from
if from < 0 || to > size {
return ""
}
var result = ""
for ( idx, char ) in self.characters.enumerated() {
if idx >= from && idx < to {
result.append( char )
}
}
return result
}
func removeWord( _ word:String ) -> String {
var result = ""
let textCharArr = Array( self.characters )
let wordCharArr = Array( word.characters )
var possibleMatch = ""
var i = 0, j = 0
while i < textCharArr.count {
if textCharArr[ i ] == wordCharArr[ j ] {
if j == wordCharArr.count - 1 {
possibleMatch = ""
j = 0
}
else {
possibleMatch.append( textCharArr[ i ] )
j += 1
}
}
else {
result.append( possibleMatch )
possibleMatch = ""
if j == 0 {
result.append( textCharArr[ i ] )
}
else {
j = 0
i -= 1
}
}
i += 1
}
return result
}}
i call it in parms
let h = Handeller()
h.Handeller(tmk: "abcdef0123456789", workingKey: "e077b34665f66eb5", pan: "1234432109874567", pin: "0000")

Related

Sending hex value to bluetooth device with iOS [duplicate]

I'm was trying to convert hexString to Array of Bytes([UInt8]) I searched everywhere but couldn't find a solution. Below is my swift 2 code
func stringToBytes(_ string: String) -> [UInt8]? {
let chars = Array(string)
let length = chars.count
if length & 1 != 0 {
return nil
}
var bytes = [UInt8]()
bytes.reserveCapacity(length/2)
for var i = 0; i < length; i += 2 {
if let a = find(hexChars, chars[i]),
let b = find(hexChars, chars[i+1]) {
bytes.append(UInt8(a << 4) + UInt8(b))
} else {
return nil
}
}
return bytes
}
Example Hex
Hex : "7661706f72"
expectedOutput : "vapor"
This code can generate the same output as your swift 2 code.
func stringToBytes(_ string: String) -> [UInt8]? {
let length = string.characters.count
if length & 1 != 0 {
return nil
}
var bytes = [UInt8]()
bytes.reserveCapacity(length/2)
var index = string.startIndex
for _ in 0..<length/2 {
let nextIndex = string.index(index, offsetBy: 2)
if let b = UInt8(string[index..<nextIndex], radix: 16) {
bytes.append(b)
} else {
return nil
}
index = nextIndex
}
return bytes
}
let bytes = stringToBytes("7661706f72")
print(String(bytes: bytes!, encoding: .utf8)) //->Optional("vapor")
Here is a sketch of how I'd do it in a more idiomatic Swift style (this might be Swift 4 only):
func toPairsOfChars(pairs: [String], string: String) -> [String] {
if string.count == 0 {
return pairs
}
var pairsMod = pairs
pairsMod.append(String(string.prefix(2)))
return toPairsOfChars(pairs: pairsMod, string: String(string.dropFirst(2)))
}
func stringToBytes(_ string: String) -> [UInt8]? {
// omit error checking: remove '0x', make sure even, valid chars
let pairs = toPairsOfChars(pairs: [], string: string)
return pairs.map { UInt8($0, radix: 16)! }
}
Following code may be help for you
extension String {
/// Create `Data` from hexadecimal string representation
///
/// This takes a hexadecimal representation and creates a `Data` object. Note, if the string has any spaces or non-hex characters (e.g. starts with '<' and with a '>'), those are ignored and only hex characters are processed.
///
/// - returns: Data represented by this hexadecimal string.
func hexadecimal() -> Data? {
var data = Data(capacity: characters.count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, options: [], range: NSMakeRange(0, characters.count)) { match, flags, stop in
let byteString = (self as NSString).substring(with: match!.range)
var num = UInt8(byteString, radix: 16)!
data.append(&num, count: 1)
}
guard data.count > 0 else {
return nil
}
return data
}
}
extension String {
/// Create `String` representation of `Data` created from hexadecimal string representation
///
/// This takes a hexadecimal representation and creates a String object from that. Note, if the string has any spaces, those are removed. Also if the string started with a `<` or ended with a `>`, those are removed, too.
init?(hexadecimal string: String) {
guard let data = string.hexadecimal() else {
return nil
}
self.init(data: data, encoding: .utf8)
}
/// - parameter encoding: The `NSStringCoding` that indicates how the string should be converted to `NSData` before performing the hexadecimal conversion.
/// - returns: `String` representation of this String object.
func hexadecimalString() -> String? {
return data(using: .utf8)?
.hexadecimal()
}
}
extension Data {
/// Create hexadecimal string representation of `Data` object.
/// - returns: `String` representation of this `Data` object.
func hexadecimal() -> String {
return map { String(format: "%02x", $0) }
.joined(separator: "")
}
}
Use like this :
let hexString = "68656c6c 6f2c2077 6f726c64"
print(String(hexadecimalString: hexString))
Or
let originalString = "hello, world"
print(originalString.hexadecimalString())
After lot searching and thinking here is how you do it
func toByteArray( _ hex:String ) -> [UInt8] {
// remove "-" from Hexadecimal
var hexString = hex.removeWord( "-" )
let size = hexString.characters.count / 2
var result:[UInt8] = [UInt8]( repeating: 0, count: size ) // array with length = size
// for ( int i = 0; i < hexString.length; i += 2 )
for i in stride( from: 0, to: hexString.characters.count, by: 2 ) {
let subHexStr = hexString.subString( i, length: 2 )
result[ i / 2 ] = UInt8( subHexStr, radix: 16 )! // ! - because could be null
}
return result
}
extension String {
func subString( _ from: Int, length: Int ) -> String {
let size = self.characters.count
let to = length + from
if from < 0 || to > size {
return ""
}
var result = ""
for ( idx, char ) in self.characters.enumerated() {
if idx >= from && idx < to {
result.append( char )
}
}
return result
}
func removeWord( _ word:String ) -> String {
var result = ""
let textCharArr = Array( self.characters )
let wordCharArr = Array( word.characters )
var possibleMatch = ""
var i = 0, j = 0
while i < textCharArr.count {
if textCharArr[ i ] == wordCharArr[ j ] {
if j == wordCharArr.count - 1 {
possibleMatch = ""
j = 0
}
else {
possibleMatch.append( textCharArr[ i ] )
j += 1
}
}
else {
result.append( possibleMatch )
possibleMatch = ""
if j == 0 {
result.append( textCharArr[ i ] )
}
else {
j = 0
i -= 1
}
}
i += 1
}
return result
}
}
Refer this video to know how I did it.
Credit : AllTech
Conversion of String to Data with nicer syntax.
static func hexStringToData(string: String) -> Data {
let stringArray = Array(string)
var data: Data = Data()
for i in stride(from: 0, to: string.count, by: 2) {
let pair: String = String(stringArray[i]) + String(stringArray[i+1])
if let byteNum = UInt8(pair, radix: 16) {
let byte = Data([byteNum])
data.append(byte)
}
else{
fatalError()
}
}
return data
}

how to encrypt/decrypt Secure QR - Code into readable format in Swift

I have successfully scan and read the stringValue from QR.But couldn't convert the stringValue to readable format.
https://uidai.gov.in/images/resource/User_manulal_QR_Code_15032019.pdf
I have tried to convert using the above procedure but couldn't succeed.
1) I have tried library to convert to BigInt and converted to binary value
let str = String(self.metadataStringValue, radix: 2)
print(str)
2)Convert the Big Integer into byte array successfully
let byteArray = Array(BigUInt(str)!.serialize())
print(byteArray)
3) Used Apple's decompression algorithm (zlib)
4) Read the value of byte array from index 0 to till first delimiter value“255” and convert this byte array value into string with encoding “ISO-8859-1”.
var firstDelimiter = ArraySlice<UInt8>()
var firstDelimiterArray = [UInt8]()
var delimiterIndex:Int = 0
for index in 0..<byteArray.count {
if byteArray[index] == 255 {
firstDelimiter = byteArray[delimiterIndex...index]
delimiterIndex = index + 1
firstDelimiterArray = firstDelimiter.map { $0 }
let data2 = Data(bytes: firstDelimiterArray, count: firstDelimiterArray.count)
print(data2 as NSData)
}
}
5)“ISO-8859-1” encoding
Couldn't convert to readbale format(I have used .isolatin1)
For swift 5,
I have decoded aadhar's secure QR Code and fetched name, DOB and gender
Referred: https://uidai.gov.in/images/resource/User_manulal_QR_Code_15032019.pdf
Install these pods
pod 'BigInt'
pod 'GzipSwift'
Import these pods
import BigInt
import Gzip
After scanning QR Code call the below function
func scannedData(code: String) {
print(code)
//Convert to BigInt
let bInt = BigInt(code, radix: 10)
//Convert to bytes
let byteData = bInt?.serialize() ?? Data()
//Convert to byte array
var data = Array(bInt?.serialize() ?? Data())
// Decompress
let decompressedData: Data
if byteData.isGzipped {
decompressedData = try! byteData.gunzipped()
data = [UInt8](decompressedData)
} else {
decompressedData = byteData
}
var firstDelimiter = ArraySlice<UInt8>()
var firstDelimiterArray = [UInt8]()
var delimiterIndex:Int = 0
var set:Int = 0
for index in 0..<data.count {
if data[index] == 255 {
set = set + 1
firstDelimiter = data[delimiterIndex..<index]
delimiterIndex = index + 1
firstDelimiterArray = firstDelimiter.map { $0 }
let sepData = Data(bytes: firstDelimiterArray, count: firstDelimiterArray.count)
// name
if set == 3 {
let name = convertString(data: sepData)
}
// DOB
if set == 4 {
let dob = convertString(data: sepData)
}
// Gender
if set == 5 {
let gender = convertString(data: sepData)
}
}
}
}
To encode the separated bytes use this function
private func convertString(data: Data) -> String {
return String(data: data, encoding: .windowsCP1250) ?? ""
}
Use this extension
extension BigInt {
public func serialize() -> Data {
var array = Array(BigUInt.init(self.magnitude).serialize())
if array.count > 0 {
if self.sign == BigInt.Sign.plus {
if array[0] >= 128 {
array.insert(0, at: 0)
}
} else if self.sign == BigInt.Sign.minus {
if array[0] <= 127 {
array.insert(255, at: 0)
}
}
}
return Data.init(bytes: array)
}
public init(_ data: Data) {
var dataArray = Array(data)
var sign: BigInt.Sign = BigInt.Sign.plus
if dataArray.count > 0 {
if dataArray[0] >= 128 {
sign = BigInt.Sign.minus
if dataArray.count > 1 {
if dataArray[0] == 255, dataArray.count > 1 {
dataArray.remove(at: 0)
} else {
dataArray[0] = UInt8(256 - Int(dataArray[0]))
}
}
}
}
let magnitude = BigUInt.init(Data.init(bytes: dataArray))
self .init(sign: sign, magnitude: magnitude)
}
}

How can split from string to array by chunks of given size

I want to split string by chunks of given size 2
Example :
String "1234567" and output should be ["12", "34", "56","7"]
You can group your collection elements (in this case Characters) every n elements as follow:
extension Collection {
func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
sequence(state: startIndex) { start in
guard start < self.endIndex else { return nil }
let end = self.index(start, offsetBy: maxLength, limitedBy: self.endIndex) ?? self.endIndex
defer { start = end }
return self[start..<end]
}
}
func subSequences(of n: Int) -> [SubSequence] {
.init(unfoldSubSequences(limitedTo: n))
}
}
let numbers = "1234567"
let subSequences = numbers.subSequences(of: 2)
print(subSequences) // ["12", "34", "56", "7"]
edit/update:
If you would like to append the exceeding characters to the last group:
extension Collection {
func unfoldSubSequencesWithTail(lenght: Int) -> UnfoldSequence<SubSequence,Index> {
let n = count / lenght
var counter = 0
return sequence(state: startIndex) { start in
guard start < endIndex else { return nil }
let end = index(start, offsetBy: lenght, limitedBy: endIndex) ?? endIndex
counter += 1
if counter == n {
defer { start = endIndex }
return self[start...]
} else {
defer { start = end }
return self[start..<end]
}
}
}
func subSequencesWithTail(n: Int) -> [SubSequence] {
.init(unfoldSubSequencesWithTail(lenght: n))
}
}
let numbers = "1234567"
let subSequencesWithTail = numbers.subSequencesWithTail(n: 2)
print(subSequencesWithTail) // ["12", "34", "567"]
var testString = "abcdefghijklmnopqrstu"
var startingPoint: Int = 0
var substringLength: Int = 1
var substringArray = [AnyHashable]()
for i in 0..<(testString.count ?? 0) / substringLength {
var substring: String = (testString as NSString).substring(with: NSRange(location: startingPoint, length: substringLength))
substringArray.append(substring)
startingPoint += substringLength
}
print("\(substringArray)")
OutPut :
(
a,
b,
c,
d,
e,
f,
g,
h,
i,
j,
k,
l,
m,
n,
o,
p,
q,
r,
s,
t,
u
)
try this
func SplitString(stringToBeSplitted:String, By:Int) -> [String]
{
var newArray = [String]()
var newStr = String()
for char in stringToBeSplitted
{
newStr += String(char)
if newStr.count == By
{
newArray.append(newStr)
newStr = ""
}
}
return newArray
}
Swift 5
extension Array {
func chunks(size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
extension String {
func chunks(size: Int) -> [String] {
map { $0 }.chunks(size: size).compactMap { String($0) }
}
}
let s = "1234567"
print(s.chunks(size: 2)) // ["12", "34", "56", "7"]
extension String {
func split(len: Int) -> [String] {
var currentIndex = 0
var array = [String]()
let length = self.characters.count
while currentIndex < length {
let startIndex = self.startIndex.advancedBy(currentIndex)
let endIndex = startIndex.advancedBy(len, limit: self.endIndex)
let substr = self.substringWithRange(Range(start: startIndex, end: endIndex))
array.append(substr)
currentIndex += len
}
return array
}
}
"123456789".split(2)
//output: ["12", "34", "56", "78", "9"]
I have write one method in objective c as below,
-(NSMutableArray*)splitString : (NSString*)str withRange : (int)range{
NSMutableArray *arr = [[NSMutableArray alloc]init];
NSMutableString *mutableStr = [[NSMutableString alloc]initWithString:str];
int j = 0;
int counter = 0;
for (int i = 0; i < str.length; i++) {
j++;
if (range == j) {
j = 0;
if (!(i == str.length - 1)) {
[mutableStr insertString:#"$" atIndex:i+1+counter];
}
counter++;
}
}
arr = (NSMutableArray*)[mutableStr componentsSeparatedByString:#"$"];
NSLog(#"%#",arr);
return arr;
}
You can call this method like,
[self splitString:#"123456" withRange:2];
and result will be,
(
12,
34,
56
)
You can also try below code:
var arrStr: [Substring] = []
let str = "1234567"
var i = 0
while i < str.count - 1 {
let index = str.index(str.startIndex, offsetBy: i)
//Below line gets current index and advances by 2
let substring = str[index..<str.index(index, offsetBy: 2)]
arrStr.append(substring)
i += 2
}
if str.count % 2 == 1 {
arrStr.append(str.suffix(1))
}
print(arrStr)
There's a stupid way, you can think about the rules of the data model.
var strOld = "123456"
print("The original string:\(strOld)")
strOld.insert("、", at: strOld.index(before: strOld.index(strOld.startIndex, offsetBy: 3)))
strOld.insert("、", at: strOld.index(before: strOld.index(strOld.startIndex, offsetBy: 6)))
print("After inserting:\(strOld)")
let str = strOld
let splitedArray = str.components(separatedBy: "、")
print("After the split of the array:\(splitedArray)")
let splitedArrayOther = str.split{$0 == "、"}.map(String.init)
print("After break up the array (method 2):\(splitedArrayOther)")
The results:
The original string:123456
After inserting:12、34、56
After the split of the array:["12", "34", "56"]
After break up the array (method 2):["12", "34", "56"]
Here's a short (and clean) solution, thanks to recursion:
extension Collection {
func chunks(ofSize size: Int) -> [SubSequence] {
// replace this by `guard count >= size else { return [] }`
// if you want to omit incomplete chunks
guard !isEmpty else { return [] }
return [prefix(size)] + dropFirst(size).chunks(ofSize: size)
}
}
The recursion should not pose a performance problem, as Swift has support for tail call optimization.
Also if Swift arrays are really fast when it comes to prepending or appending elements (like the Objective-C ones are), then the array operations should be fast.
Thus you get both fast and readable code (assuming my array assumptions are true).

Epub Font Mangling is not working

I am creating an EPUB 3 reader for iOS using Swift 2.
The problem I'm currently facing is with font obfuscation / font mangling. I've read a tutorial that goes over how to do that in Swift, and integrated it into my project with some adaptations.
When I load an obfuscated epub into my app, the fonts are not loaded correctly and fall back to other system fonts. When I load an epub with the same fonts but not obfuscated, everything looks fine. Obviously, that means there's something wrong with my obfuscation code, but I can't for the life of me find the error.
Here's my code:
public struct Crypto {
public func obfuscateFontIDPF(data:NSData, key:String) -> NSData {
let source = data
var destination = [UInt8]()
let shaKey = key.sha1()
let keyData = shaKey.utf8Array
var arr = [UInt8](count: source.length, repeatedValue: 0)
source.getBytes(&arr, length:source.length)
var outer = 0
while outer < 52 && arr.isEmpty == false {
var inner = 0
while inner < 20 && arr.isEmpty == false {
let byte = arr.removeAtIndex(0) //Assumes read advances file position
let sourceByte = byte
let keyByte = keyData[inner]
let obfuscatedByte = sourceByte ^ keyByte
destination.append(obfuscatedByte)
inner++
}
outer++
}
if arr.isEmpty == false {
while arr.isEmpty == false {
let byte = arr.removeAtIndex(0)
destination.append(byte)
}
}
let newData = NSData(bytes: &destination, length: destination.count*sizeof(UInt8))
return newData
}
}
extension String {
func sha1() -> String {
var selfAsSha1 = ""
if let data = self.dataUsingEncoding(NSUTF8StringEncoding)
{
var digest = [UInt8](count: Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
for index in 0..<CC_SHA1_DIGEST_LENGTH
{
selfAsSha1 += String(format: "%02x", digest[Int(index)])
}
}
return selfAsSha1
}
var utf8Array: [UInt8] {
return Array(utf8)
}
}
And here I call the obfuscation method:
func parserDidEndDocument(parser: NSXMLParser) {
if encryptedFilePaths!.count != 0 {
for file in encryptedFilePaths! {
let epubMainDirectoryPath = NSString(string: epubBook!.epubMainFolderPath!).stringByDeletingLastPathComponent
let fullFilePath = epubMainDirectoryPath.stringByAppendingString("/" + file)
let url = NSURL(fileURLWithPath: fullFilePath)
if let source = NSData(contentsOfURL: url) {
let decryptedFont = Crypto().obfuscateFontIDPF(source, key: self.epubBook!.encryptionKey!)
do {
try decryptedFont.writeToFile(fullFilePath, options: .DataWritingAtomic)
} catch {
print(error)
}
}
}
}
}
If you see where the error might be, please let me know.
I figured it out, here is the working code:
private func obfuscateData(data: NSData, key: String) -> NSData {
var destinationBytes = [UInt8]()
// Key needs to be SHA1 hash with length of exactly 20 chars
let hashedKeyBytes = generateHashedBytesFromString(key)
var sourceBytes = [UInt8](count: data.length, repeatedValue: 0)
data.getBytes(&sourceBytes, length: data.length)
var outerCount = 0
while outerCount < 52 && sourceBytes.isEmpty == false {
var innerCount = 0
while innerCount < 20 && sourceBytes.isEmpty == false {
let sourceByte = sourceBytes.removeAtIndex(0)
let keyByte = hashedKeyBytes[innerCount]
let obfuscatedByte = (sourceByte ^ keyByte)
destinationBytes.append(obfuscatedByte)
innerCount += 1
}
outerCount += 1
}
destinationBytes.appendContentsOf(sourceBytes)
let destinationData = NSData(bytes: &destinationBytes, length: destinationBytes.count*sizeof(UInt8))
sourceBytes.removeAll(keepCapacity: false)
destinationBytes.removeAll(keepCapacity: false)
return destinationData
}
/// Convert the key string to a SHA1 hashed Byte Array
private func generateHashedBytesFromString(string: String) -> [UInt8] {
var resultBytes = [UInt8]()
var hashedString = string.sha1()
for _ in 0.stride(to: hashedString.characters.count, by: 2) {
let character = "0x\(hashedString.returnTwoCharacters())"
resultBytes.append(UInt8(strtod(character, nil)))
}
return resultBytes
}
extension String {
func sha1() -> String {
var selfAsSha1 = ""
if let data = self.dataUsingEncoding(NSUTF8StringEncoding) {
var digest = [UInt8](count: Int(CC_SHA1_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA1(data.bytes, CC_LONG(data.length), &digest)
for index in 0..<CC_SHA1_DIGEST_LENGTH {
selfAsSha1 += String(format: "%02x", digest[Int(index)])
}
}
return selfAsSha1
}
mutating func returnTwoCharacters() -> String {
var characters: String = ""
characters.append(self.removeAtIndex(startIndex))
characters.append(self.removeAtIndex(startIndex))
return characters
}
}

Converting Hex String to NSData in Swift

I got the code to convert String to HEX-String in Objective-C:
- (NSString *) CreateDataWithHexString:(NSString*)inputString {
NSUInteger inLength = [inputString length];
unichar *inCharacters = alloca(sizeof(unichar) * inLength);
[inputString getCharacters:inCharacters range:NSMakeRange(0, inLength)];
UInt8 *outBytes = malloc(sizeof(UInt8) * ((inLength / 2) + 1));
NSInteger i, o = 0;
UInt8 outByte = 0;
for (i = 0; i < inLength; i++) {
UInt8 c = inCharacters[i];
SInt8 value = -1;
if (c >= '0' && c <= '9') value = (c - '0');
else if (c >= 'A' && c <= 'F') value = 10 + (c - 'A');
else if (c >= 'a' && c <= 'f') value = 10 + (c - 'a');
if (value >= 0) {
if (i % 2 == 1) {
outBytes[o++] = (outByte << 4) | value;
outByte = 0;
} else {
outByte = value;
}
} else {
if (o != 0) break;
}
}
NSData *a = [[NSData alloc] initWithBytesNoCopy:outBytes length:o freeWhenDone:YES];
NSString* newStr = [NSString stringWithUTF8String:[a bytes]];
return newStr;
}
I want the same in Swift. Can anybody translate this code in Swift, or is there any easy way to do this in Swift?
This is my hex string to Data routine:
extension String {
/// Create `Data` from hexadecimal string representation
///
/// This creates a `Data` object from hex string. Note, if the string has any spaces or non-hex characters (e.g. starts with '<' and with a '>'), those are ignored and only hex characters are processed.
///
/// - returns: Data represented by this hexadecimal string.
var hexadecimal: Data? {
var data = Data(capacity: count / 2)
let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
regex.enumerateMatches(in: self, range: NSRange(startIndex..., in: self)) { match, _, _ in
let byteString = (self as NSString).substring(with: match!.range)
let num = UInt8(byteString, radix: 16)!
data.append(num)
}
guard data.count > 0 else { return nil }
return data
}
}
And for the sake of completeness, this is my Data to hex string routine:
extension Data {
/// Hexadecimal string representation of `Data` object.
var hexadecimal: String {
return map { String(format: "%02x", $0) }
.joined()
}
}
Note, as shown in the above, I generally only convert between hexadecimal representations and NSData instances (because if the information could have been represented as a string you probably wouldn't have created a hexadecimal representation in the first place). But your original question wanted to convert between hexadecimal representations and String objects, and that might look like so:
extension String {
/// Create `String` representation of `Data` created from hexadecimal string representation
///
/// This takes a hexadecimal representation and creates a String object from that. Note, if the string has any spaces, those are removed. Also if the string started with a `<` or ended with a `>`, those are removed, too.
///
/// For example,
///
/// String(hexadecimal: "<666f6f>")
///
/// is
///
/// Optional("foo")
///
/// - returns: `String` represented by this hexadecimal string.
init?(hexadecimal string: String, encoding: String.Encoding = .utf8) {
guard let data = string.hexadecimal() else {
return nil
}
self.init(data: data, encoding: encoding)
}
/// Create hexadecimal string representation of `String` object.
///
/// For example,
///
/// "foo".hexadecimalString()
///
/// is
///
/// Optional("666f6f")
///
/// - parameter encoding: The `String.Encoding` that indicates how the string should be converted to `Data` before performing the hexadecimal conversion.
///
/// - returns: `String` representation of this String object.
func hexadecimalString(encoding: String.Encoding = .utf8) -> String? {
return data(using: encoding)?
.hexadecimal
}
}
You could then use the above like so:
let hexString = "68656c6c 6f2c2077 6f726c64"
print(String(hexadecimal: hexString))
Or,
let originalString = "hello, world"
print(originalString.hexadecimalString())
For permutations of the above for earlier Swift versions, see the revision history of this question.
convert hex string to data and string:
Swift1
func dataWithHexString(hex: String) -> NSData {
var hex = hex
let data = NSMutableData()
while(countElements(hex) > 0) {
var c: String = hex.substringToIndex(advance(hex.startIndex, 2))
hex = hex.substringFromIndex(advance(hex.startIndex, 2))
var ch: UInt32 = 0
NSScanner(string: c).scanHexInt(&ch)
data.appendBytes(&ch, length: 1)
}
return data
}
use:
let data = dataWithHexString("68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
if let string = NSString(data: data, encoding: 1) {
print(string) // hello, world
}
Swift2
func dataWithHexString(hex: String) -> NSData {
var hex = hex
let data = NSMutableData()
while(hex.characters.count > 0) {
let c: String = hex.substringToIndex(hex.startIndex.advancedBy(2))
hex = hex.substringFromIndex(hex.startIndex.advancedBy(2))
var ch: UInt32 = 0
NSScanner(string: c).scanHexInt(&ch)
data.appendBytes(&ch, length: 1)
}
return data
}
use:
let data = dataWithHexString("68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
if let string = String(data: data, encoding: NSUTF8StringEncoding) {
print(string) //"hello, world"
}
Swift3
func dataWithHexString(hex: String) -> Data {
var hex = hex
var data = Data()
while(hex.characters.count > 0) {
let c: String = hex.substring(to: hex.index(hex.startIndex, offsetBy: 2))
hex = hex.substring(from: hex.index(hex.startIndex, offsetBy: 2))
var ch: UInt32 = 0
Scanner(string: c).scanHexInt32(&ch)
var char = UInt8(ch)
data.append(&char, count: 1)
}
return data
}
use:
let data = dataWithHexString(hex: "68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
let string = String(data: data, encoding: .utf8) // "hello, world"
Swift4
func dataWithHexString(hex: String) -> Data {
var hex = hex
var data = Data()
while(hex.count > 0) {
let subIndex = hex.index(hex.startIndex, offsetBy: 2)
let c = String(hex[..<subIndex])
hex = String(hex[subIndex...])
var ch: UInt32 = 0
Scanner(string: c).scanHexInt32(&ch)
var char = UInt8(ch)
data.append(&char, count: 1)
}
return data
}
use:
let data = dataWithHexString(hex: "68656c6c6f2c20776f726c64") // <68656c6c 6f2c2077 6f726c64>
let string = String(data: data, encoding: .utf8) // "hello, world"
Swift 4 & Swift 5 implementation:
init?(hexString: String) {
let len = hexString.count / 2
var data = Data(capacity: len)
var i = hexString.startIndex
for _ in 0..<len {
let j = hexString.index(i, offsetBy: 2)
let bytes = hexString[i..<j]
if var num = UInt8(bytes, radix: 16) {
data.append(&num, count: 1)
} else {
return nil
}
i = j
}
self = data
}
Usage:
let data = Data(hexString: "0a1b3c4d")
Swift 5
extension Data {
init?(hex: String) {
guard hex.count.isMultiple(of: 2) else {
return nil
}
let chars = hex.map { $0 }
let bytes = stride(from: 0, to: chars.count, by: 2)
.map { String(chars[$0]) + String(chars[$0 + 1]) }
.compactMap { UInt8($0, radix: 16) }
guard hex.count / bytes.count == 2 else { return nil }
self.init(bytes)
}
}
Here is my Swift 5 way to do it:
does take care of "0x" prefixes
use subscript instead of allocated Array(), no C style [i+1] too
add .hexadecimal to String.data(using encoding:) -> Data?
.
String Extension:
extension String {
enum ExtendedEncoding {
case hexadecimal
}
func data(using encoding:ExtendedEncoding) -> Data? {
let hexStr = self.dropFirst(self.hasPrefix("0x") ? 2 : 0)
guard hexStr.count % 2 == 0 else { return nil }
var newData = Data(capacity: hexStr.count/2)
var indexIsEven = true
for i in hexStr.indices {
if indexIsEven {
let byteRange = i...hexStr.index(after: i)
guard let byte = UInt8(hexStr[byteRange], radix: 16) else { return nil }
newData.append(byte)
}
indexIsEven.toggle()
}
return newData
}
}
Usage:
"5413".data(using: .hexadecimal)
"0x1234FF".data(using: .hexadecimal)
Tests:
extension Data {
var bytes:[UInt8] { // fancy pretty call: myData.bytes -> [UInt8]
return [UInt8](self)
}
// Could make a more optimized one~
func hexa(prefixed isPrefixed:Bool = true) -> String {
return self.bytes.reduce(isPrefixed ? "0x" : "") { $0 + String(format: "%02X", $1) }
}
}
print("000204ff5400".data(using: .hexadecimal)?.hexa() ?? "failed") // OK
print("0x000204ff5400".data(using: .hexadecimal)?.hexa() ?? "failed") // OK
print("541".data(using: .hexadecimal)?.hexa() ?? "failed") // fails
print("5413".data(using: .hexadecimal)?.hexa() ?? "failed") // OK
Here's a simple solution I settled on:
extension NSData {
public convenience init(hexString: String) {
var index = hexString.startIndex
var bytes: [UInt8] = []
repeat {
bytes.append(hexString[index...index.advancedBy(1)].withCString {
return UInt8(strtoul($0, nil, 16))
})
index = index.advancedBy(2)
} while index.distanceTo(hexString.endIndex) != 0
self.init(bytes: &bytes, length: bytes.count)
}
}
Usage:
let data = NSData(hexString: "b8dfb080bc33fb564249e34252bf143d88fc018f")
Output:
print(data)
>>> <b8dfb080 bc33fb56 4249e342 52bf143d 88fc018f>
Update 6/29/2016
I updated the initializer to handle malformed data (i.e., invalid characters or odd number of characters).
public convenience init?(hexString: String, force: Bool) {
let characterSet = NSCharacterSet(charactersInString: "0123456789abcdefABCDEF")
for scalar in hexString.unicodeScalars {
if characterSet.characterIsMember(UInt16(scalar.value)) {
hexString.append(scalar)
}
else if !force {
return nil
}
}
if hexString.characters.count % 2 == 1 {
if force {
hexString = "0" + hexString
}
else {
return nil
}
}
var index = hexString.startIndex
var bytes: [UInt8] = []
repeat {
bytes.append(hexString[index...index.advancedBy(1)].withCString {
return UInt8(strtoul($0, nil, 16))
})
index = index.advancedBy(2)
} while index.distanceTo(hexString.endIndex) != 0
self.init(bytes: &bytes, length: bytes.count)
}
Here is my take on converting hexadecimal string to Data using Swift 4:
extension Data {
private static let hexRegex = try! NSRegularExpression(pattern: "^([a-fA-F0-9][a-fA-F0-9])*$", options: [])
init?(hexString: String) {
if Data.hexRegex.matches(in: hexString, range: NSMakeRange(0, hexString.count)).isEmpty {
return nil // does not look like a hexadecimal string
}
let chars = Array(hexString)
let bytes: [UInt8] =
stride(from: 0, to: chars.count, by: 2)
.map {UInt8(String([chars[$0], chars[$0+1]]), radix: 16)}
.compactMap{$0}
self = Data(bytes)
}
var hexString: String {
return map { String(format: "%02hhx", $0) }.joined()
}
}
(I threw in a small feature for converting back to hex string I found in this answer)
And here is how you would use it:
let data = Data(hexString: "cafecafe")
print(data?.hexString) // will print Optional("cafecafe")
One more solution that is simple to follow and leverages swifts built-in hex parsing
func convertHexToBytes(_ str: String) -> Data? {
let values = str.compactMap { $0.hexDigitValue } // map char to value of 0-15 or nil
if values.count == str.count && values.count % 2 == 0 {
var data = Data()
for x in stride(from: 0, to: values.count, by: 2) {
let byte = (values[x] << 4) + values[x+1] // concat high and low bits
data.append(UInt8(byte))
}
return data
}
return nil
}
let good = "e01AFd"
let bad = "e0671"
let ugly = "GT40"
print("\(convertHexToBytes(good))") // Optional(3 bytes)
print("\(convertHexToBytes(bad))") // nil
print("\(convertHexToBytes(ugly))") // nil
The code worked for me in Swift 3.0.2.
extension String {
/// Expanded encoding
///
/// - bytesHexLiteral: Hex string of bytes
/// - base64: Base64 string
enum ExpandedEncoding {
/// Hex string of bytes
case bytesHexLiteral
/// Base64 string
case base64
}
/// Convert to `Data` with expanded encoding
///
/// - Parameter encoding: Expanded encoding
/// - Returns: data
func data(using encoding: ExpandedEncoding) -> Data? {
switch encoding {
case .bytesHexLiteral:
guard self.characters.count % 2 == 0 else { return nil }
var data = Data()
var byteLiteral = ""
for (index, character) in self.characters.enumerated() {
if index % 2 == 0 {
byteLiteral = String(character)
} else {
byteLiteral.append(character)
guard let byte = UInt8(byteLiteral, radix: 16) else { return nil }
data.append(byte)
}
}
return data
case .base64:
return Data(base64Encoded: self)
}
}
}
Swift 5
With support iOS 13 and iOS2...iOS12.
extension String {
var hex: Data? {
var value = self
var data = Data()
while value.count > 0 {
let subIndex = value.index(value.startIndex, offsetBy: 2)
let c = String(value[..<subIndex])
value = String(value[subIndex...])
var char: UInt8
if #available(iOS 13.0, *) {
guard let int = Scanner(string: c).scanInt32(representation: .hexadecimal) else { return nil }
char = UInt8(int)
} else {
var int: UInt32 = 0
Scanner(string: c).scanHexInt32(&int)
char = UInt8(int)
}
data.append(&char, count: 1)
}
return data
}
}
Swift 5
There is a compact implementation of initialize Data instance from hex string using a regular expression. It searches hex numbers inside a string and combine them to a result data so that it can support different formats of hex representations:
extension Data {
private static let regex = try! NSRegularExpression(pattern: "([0-9a-fA-F]{2})", options: [])
/// Create instance from string with hex numbers.
init(from: String) {
let range = NSRange(location: 0, length: from.utf16.count)
let bytes = Self.regex.matches(in: from, options: [], range: range)
.compactMap { Range($0.range(at: 1), in: from) }
.compactMap { UInt8(from[$0], radix: 16) }
self.init(bytes)
}
/// Hex string representation of data.
var hex: String {
map { String($0, radix: 16) }.joined()
}
}
Examples:
let data = Data(from: "0x11223344aabbccdd")
print(data.hex) // Prints "11223344aabbccdd"
let data2 = Data(from: "11223344aabbccdd")
print(data2.hex) // Prints "11223344aabbccdd"
let data3 = Data(from: "11223344 aabbccdd")
print(data3.hex) // Prints "11223344aabbccdd"
let data4 = Data(from: "11223344 AABBCCDD")
print(data4.hex) // Prints "11223344aabbccdd"
let data5 = Data(from: "Hex: 0x11223344AABBCCDD")
print(data5.hex) // Prints "11223344aabbccdd"
let data6 = Data(from: "word[0]=11223344 word[1]=AABBCCDD")
print(data6.hex) // Prints "11223344aabbccdd"
let data7 = Data(from: "No hex")
print(data7.hex) // Prints ""
Handles prefixes
Ignores invalid characters and incomplete bytes
Uses Swift built in hex character parsing
Doesn't use subscripts
extension Data {
init(hexString: String) {
self = hexString
.dropFirst(hexString.hasPrefix("0x") ? 2 : 0)
.compactMap { $0.hexDigitValue.map { UInt8($0) } }
.reduce(into: (data: Data(capacity: hexString.count / 2), byte: nil as UInt8?)) { partialResult, nibble in
if let p = partialResult.byte {
partialResult.data.append(p + nibble)
partialResult.byte = nil
} else {
partialResult.byte = nibble << 4
}
}.data
}
}
Supposing your string is even size, you can use this to convert to hexadecimal and save it to Data:
Swift 5.2
func hex(from string: String) -> Data {
.init(stride(from: 0, to: string.count, by: 2).map {
string[string.index(string.startIndex, offsetBy: $0) ... string.index(string.startIndex, offsetBy: $0 + 1)]
}.map {
UInt8($0, radix: 16)!
})
}

Resources