Converting base64 string to hex to readable string: Swift - swift

I am working with some 3rd party data. The data they are returning from our request is suppose to be base64 encoded into a string. They provide these instructions for converting it to a readable format:
*First, converting the Base64 string to hexadecimals using the open-source "tomeko" online tool: http://tomeko.net/online_tools/base64.php?lang=en.
Second, in the SAE J2735 standard, all messages are sent as a MessageFrame. The MessageFrame contains information about which particular type of message is included within the MessageFrame. The proper way to decode the hexadecimals from step #1, is to select MessageFrame under the ASN.1 message in the open-source Marben online decoder tool: http://www.marben-products.com/asn.1/services/decoder-asn1-automotive.html.
*
I'm working on an iPhone app so reaching out to these sites for the conversion is not optimal. I decoded the B64 string into hex with this code:
func convert64EncodedToHex(_ data:Data) -> String {
return data.map{ String(format: "%02x", $0) }.joined()
}
which came back as so:
5B224142 4E464141 41414F51 6F414141 63414545 4E427055 476C5141 45434B67 796C6A4C 49414442 44515A2B 686E3641 4341686F 4D77517A 42414251 51304753 675A4B41 41774961 44536F4E 4B674163 454E426D 43475949 41514347 677A7544 4F34225D
But when I plug that into the Marben decoder it fails:
<error>
<description>Unexpected end of stream reached when decoding</description>
<nature>fr.marben.asnsdk.japi.InconsistentStructureException</nature>
<ErrorOffset>72</ErrorOffset>
<ValuePath>SPAT.intersections.IntersectionState#1.states.MovementState#1.state-time-speed.MovementEvent#1.regional.SEQUENCE#1.regExtValue</ValuePath>
</error>
Eventually I would need to decode the hex into readable string in the app so I was wondering:
Why my b64 to hex code seems to be failing
how to transform hex to readable string
EDIT
OK, on the Marben site I was selecting the wrong drop down for decoding. Selecting MessageFrame provided a successful result so the b64 to hex I have is working. New problem arose from that is I can't decipher these results:
68 bytes decoded.
* DECODING SUCCESSFUL *

A couple of problems.
The hex string you provided translates to an original response of:
["ABNFAAAAOQoAAAcAEENBpUGlQAECKgyljLIADBDQZ+hn6ACAhoMwQzBABQQ0GSgZKAAwIaDSoNKgAcENBmCGYIAQCGgzuDO4"]
Perhaps they sent it to you in a JSON array? Bottom line, you need to trim out the [" and "] before you do anything else with this. For example, if it was JSON, you could parse the JSON before you base64-decode it:
do {
let array = try JSONDecoder().decode([String].self, from: originalJSONData)
if let base64String = array.first {
// use `base64String` here
}
} catch {
print(error)
}
If you want the data associated with that base64 string, you'd do something like:
let base64String = "ABNFAAAAOQoAAAcAEENBpUGlQAECKgyljLIADBDQZ+hn6ACAhoMwQzBABQQ0GSgZKAAwIaDSoNKgAcENBmCGYIAQCGgzuDO4"
let payload = Data(base64Encoded: base64String)!
If you merely want to display that as a hex string (I'm not sure why you'd want to do that), the easiest way is:
print(payload as NSData)
That would display
<00134500 0000390a 00000700 104341a5 41a54001 022a0ca5 8cb2000c 10d067e8 67e80080 86833043 30400504 34192819 28003021 a0d2a0d2 a001c10d 06608660 80100868 33b833b8>
If you really need that hex String representation, you can use the routine you have in your question (but do it on the base64-decoded payload, rather than the base64 string):
let payloadString = payload.map { String(format: "%02x", $0) }
.joined()
print(payloadString)
That will return:
001345000000390a00000700104341a541a54001022a0ca58cb2000c10d067e867e8008086833043304005043419281928003021a0d2a0d2a001c10d066086608010086833b833b8
Personally, the hex strings (in step 3 and 4) are interesting if you want to visually examine the binary payload, but probably you really need the original payload (in step 2). As I look at this data, it's not immediately obvious what this "3rd party data" returned, so I cannot comment further on that, but you presumably have some mechanism to consume this payload.

Related

Conversion from String to binary and then to base64 format

Trying to create a signature by using RFC 2104-compliant HMAC with the SHA256 hash algorithm. I am half-way done but stuck in converting a string to binary and then to base64 format.
Here is the instruction I am following.
Here is the code I made
let stringToSign = "GET\nwebservices.amazon.com\n/onca/xml\nAWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&AssociateTag=mytag-20&ItemId=0679722769&Operation=ItemLookup&ResponseGroup=Images%2CItemAttributes%2COffers%2CReviews&Service=AWSECommerceService&Timestamp=2014-08-18T12%3A00%3A00Z&Version=2013-08-01"
let beforeCoversion = stringToSign.hmac(algorithm: .SHA256, key: "1234567890")
let binary = beforeCoversion.data(using: .utf8, allowLossyConversion: false)
let afterCoversion = binary?.base64EncodedString(options: [.lineLength64Characters])
print(beforeCoversion)
print(afterCoversion!)
Print
8fb6d93342d767d797799aee4ea5a6d8322f0d8554537c313cfa69fa25f1cd07
OGZiNmQ5MzM0MmQ3NjdkNzk3Nzk5YWVlNGVhNWE2ZDgzMjJmMGQ4NTU0NTM3YzMx
M2NmYTY5ZmEyNWYxY2QwNw==
I can see that I get 8fb6d93342d767d797799aee4ea5a6d8322f0d8554537c313cfa69fa25f1cd07 so my conversion is failed in converting a string to binary and then to base64 format. I believe beforeCoversion.data(using: .utf8, allowLossyConversion: false) can be used for converting a string to binary and binary?.base64EncodedString(options: [.lineLength64Characters]) can be used for converting to base64 format. Is that correct? sAny suggestions?
Easy way to solve this if you use amazon-api
pod 'AWSAPIGateway'
Then
let dataToSign = stringToSign.data(using: String.Encoding.utf8)
let conversion = AWSSignatureSignerUtility.hmacSign(dataToSign, withKey: "1234567890", usingAlgorithm: UInt32(kCCHmacAlgSHA256))!
Thanks Roozbeh Zabihollahi for the answer in Amazon Product Advertising API Signature in iOS

Swift 3: Converting Data to String returns a nil value

Converting Data to String returns a nil value.
Code:
// thus unwraps the image
if let image = image{
print("Saving image data")
// don't unwrap here
if let data = UIImagePNGRepresentation(image){
let str = String(data: data, encoding: .utf8)
print(str)
}
}
I don't know the reason.
Also, how do I convert the String back to Data?
This doesn't work because when you interpret the bytes of the Image as a String, the string is invalid. Not every jumble of data is a valid utf8 string. i.e. not every collection of n bits (8, sometimes 16) are a valid utf8 code point. The Swift String api loops through the data object you pass it to validate that it is a valid string. In your case, theres no reason to think that this Data is a valid string, so it doesn't work.
A good read on utf8:
https://www.objc.io/issues/9-strings/unicode/

Alamofire + swiftyJSON array parsing

When I got JSON {"categories": "[\"a/b/c\",\"d\"]"} from server,
Then How can I parse it to ["a/b/c", "d"]
When I using .arrayValue, then it always return []
You have an array represented as raw JSON string within your JSON. You have three options:
Try to manually scan through replacing occurrences of \" (which you'll have to confusingly escape both the backslash character and the quotation mark encountered with a backslash when you write your code, e.g. "\\\"") before you parse the JSON. To do this, you'd probably use responseData rather than responseJSON, do your manual replacement of characters, and then manually parse it yourself with NSJSONSerialization. The downside here is that you might want to check for other escaped characters, too (e.g. what if the nested JSON was pretty printed, then you might have \n or even \t in there, too, which you'd want to convert as well).
Manually run JSON parsing again for each of those values that contain a JSON string in the responseObject. If you're stuck with the existing JSON, I think this is probably safest.
For example, if the raw json was really just:
{"categories": "[\"a/b/c\",\"d\"]"}
Then you could do something like:
Alamofire.request(request)
.responseJSON { response in
guard response.result.error == nil else {
print(response.result.error!)
return
}
do {
if let dictionary = response.result.value as? [String: String],
let categoryData = dictionary["categories"]?.dataUsingEncoding(NSUTF8StringEncoding),
let categories = try NSJSONSerialization.JSONObjectWithData(categoryData, options: []) as? [String]
{
let result = ["categories" : categories]
print(result)
}
} catch {
print(error)
}
}
Then the result would be:
["categories": ["a/b/c", "d"]]
Fix the web service that's generating this JSON so that it's not doing this silliness. This is probably the best solution, though it will take some detective work to figure out why/how the web service put JSON inside JSON. I know that you say you can't change the server side, but you really should escalate this to someone on the server team to fix this. It's silly to write client code to work around some mistake (either a mistake in the server code itself, or how the server was provided the data in the first place).
First up, the response you're getting from the server is a String and not Array. Hence you'll get empty array when you do .arrayValue . If you want to convert the string into an array, first you need to remove the "[" & "]" and then you need to do the componentsSeparatedByString with string as "," for the resultant string. You can use the following code snippet to do that:
let str = "[\"a/b/c\",\"d\"]"
let filteredString = String (str.characters.filter { $0 != "[" && $0 != "]"})
print(filteredString)
let filteredStringArray = filteredString.componentsSeparatedByString(",")
print(filteredStringArray)
HTH :)

Swift Conversion UTF16 to UTF8 and back

I'm building an app in Swift an I'm using Backendless as my backend. Turns out their database is UTF8 and thus I can't save emojis without converting the String first.
I can't seem to find the right way to make this conversion to UTF8. I tried this:
let encoding = processedText.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
But after this operation the emojis look like this:
%F0%9F%99%84%F0%9F%98%80%F0%9F%98%92%F0%9F%98%89%F0%9F%98%B6%F0%9F%98%B6%F0%9F%98%80%F0%9F%99%81
And I tried this:
class func stringToUTF8String (string: String) -> String? {
let encodedData = string.dataUsingEncoding(NSUTF8StringEncoding)!
let attributedOptions = [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType]
do{
let attributedString = try NSAttributedString(data: encodedData, options: attributedOptions, documentAttributes: nil)
return attributedString.string
}catch _ {
}
return nil
}
And the emojis look like this:
🤔🤔👅ðŸ™ðŸ˜‚😭😎😉😅😉
Does anyone have any suggestions? Thanks
First, to create a String from NSData with utf8 encoding you use
String(data: theData, encoding: NSUTF8StringEncoding)
Second, swift String's already are unicode compliant. You do not have to convert them as they already do that. You can access different encodings with their respective properties, e.g. String.utf8, String.utf16, and so on.
Third, to have NSAttributedString properly utf8 encode your string from data you have to add NSCharacterEncodingDocumentAttribute key to the attributedOptions dictionary with the value NSUTF8StringEncoding.
Final notes, I don't know if that's a partial method, but attributed string shouldn't be used just to encode a string.
Here is NSAttributedString encoding the data in some format returning gibberish.
Here is NSAttributedString encoding data as utf8 and returning correct text.
Here is encoding a string as utf8 string.
I know it's an image, but I wanted the results to show. If these don't work, the database may be stripping bits. Which sucks, also have no idea what to do then, and you probably shouldn't use that database if you want unicode support.

Swift NSData from base64encoded string returns nil

I'm communicating with a server in Swift retrieving image data. The incoming data is encoded as a base64 string. I am able to correctly receive and display the encoded strings. When I go to use the NSData class to decode the string back to binary data and display...
println(NSData(base64EncodedString: imageString, options: NSDataBase64DecodingOptions(0)))
The output is
nil
nil
nil
nil
nil
nil
One for each of the images received.
I've also tried
println(NSData(base64EncodedString: imageString, options: nil))
and the same results. Is there anything I am missing along the way?? I would put the image strings up but they are massively long...
For others that may be having this issue, make sure your Base64 encoded string has a length divisible by 4 (= should be used to pad the length).
See this StackOverflow answer here: https://stackoverflow.com/a/36366421/330494
Try to use IgnoreUnknownCharacters option.
Or try to use initWithBase64EncodedString from NSDataAdditions
This can also happen if the input is so-called "URL Safe" Base64 data. This data has the + symbol replaced by the - symbol, and the / symbol replaced by the _ symbol.
Fortunately it's straightforward to convert it:
inputString = [[inputString stringByReplacingOccurrencesOfString:#"-" withString:#"+"] stringByReplacingOccurrencesOfString:#"_" withString:#"/"];
A full list of variants is available on Wikipedia.
Based on Frank Schmitt's and Barlow Tucker's answers I've created an extension to Data to better handle base64 encoding:
extension Data {
static func decodeUrlSafeBase64(_ value: String) throws -> Data {
var stringtoDecode: String = value.replacingOccurrences(of: "-", with: "+")
stringtoDecode = stringtoDecode.replacingOccurrences(of: "_", with: "/")
switch (stringtoDecode.utf8.count % 4) {
case 2:
stringtoDecode += "=="
case 3:
stringtoDecode += "="
default:
break
}
guard let data = Data(base64Encoded: stringtoDecode, options: [.ignoreUnknownCharacters]) else {
throw NSError(domain: "decodeUrlSafeBase64", code: 1,
userInfo: [NSLocalizedDescriptionKey: "Can't decode base64 string"])
}
return data
}
}
so in your code, you can use it like this:
let baseEncodeText = "(.....)" //your base64 encoded string
let data = try Data.decodeUrlSafeBase64(baseEncodeText)