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
Related
Can someone explain the behavior of the function below? Some have suggested to not use NSData. Do you have better alternatives to mention? If the returned value is Base64Encoded can I decode on one of the online encoders/decoders? Thanks.
func stringToData(message: String) -> NSData? {
let strData = NSData(base64Encoded: message, options: NSData.Base64DecodingOptions.ignoreUnknownCharacters)
return strData
}
NSData(base64Encoded:options:) is documented to attempt to initialize a data object with the given Base64 encoded string—and return nil if it fails. In other words; it decodes a Base64 encoded string as an NSData object.
In Swift, you would likely use the base64EncodedString() function and the Data(base64Encoded:) initializer on the Data type to encode and decode data as Base64 strings, for example like this:
let originalData = Data(bytes: [1,2,3,4,5,6,7,8,9,10,11,12])
let encodedAsBase64String = originalData.base64EncodedString()
// "AQIDBAUGBwgJCgsM"
let decodedData = Data(base64Encoded: encodedAsBase64String) // is optional because the decoding can fail
// 12 bytes: <01020304 05060708 090A0B0C>
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.
I'm using the Vapor framework to download a PDF file :
let logpw = "myLogin:passWord"
let url = "https://someRESTsite/invoices/1.pdf"
let utf8str = logpw.data(using: String.Encoding.utf8)
let base64Encoded = utf8str?.base64EncodedString()
let response = try drop.client.get(url, headers:["Authorization":"Basic " + base64Encoded!])
this works fine. Note that I'm base64 encoding the login/pw for basic auth and this works for logging in and getting the file. Now I have to embed that PDF into an XML file in base64 using similar code:
if let bodyBytes = response.body.bytes {
let bodyByteString = try String(bytes: bodyBytes)
let utf8String = bodyByteString(using: String.Encoding.utf8)
let base64String = utf8String?.base64EncodedString()
}
the result is a string that actually really looks like a base64 string, but it's different than converting the same PDF using an online tool (I tried 2 which gave the same result).
Where is my mistake?
I am trying to encrypt value using swift sodium with given public key.
However, the encrypted value is not the same as what's produced on server side.
I am not sure whether this piece of coding is right in swift.
The steps are similar to how its done in java.
Assume public key is in base64 string format.
Java:
String pubKey = "w6mjd11n9w9ncKfcuR888Ygi02ou+46ocIajlcUEmQ=";
String secret = "hithere"
byte[] pubKeyBytes = Base64.decode(pubKey,0);
SealedBox sealedDeal = new SealedBox(pubKeyBytes);
byte[] c = sealedDeal.encrypt(secret.getBytes());
String ciphertext = Base64.encodeToString(c, 0);
Swift:
let pubKey = "w6mjd11n9w9ncKfcuR888Ygi02ou+46ocIajlcUEmQ="
let dataDecoded:NSData = NSData(base64Encoded: pubKey, options: NSData.Base64DecodingOptions(rawValue: 0))!
let secret = "hithere".toData()!
let c : Data = sodium.box.seal(message: secret, recipientPublicKey: dataDecoded as Box.PublicKey)!
let ciphertext = c.base64EncodedString(options: .init(rawValue: 0))
Please tell me know what's wrong with the swift equivalent coding.
Thanks alot.
The encrypted value is supposed to be different, so that ciphertexts resulting from equivalent plaintexts are indistinguishable (see Ciphertext indistinguishability).
sodium.box.seal internally generates new nonce every time you are encrypting message, #Max is right, this is normal behave
You can use Detached mode to give same nonce, but this is a very bad idea
In your example you have used Anonymous Encryption I suggest you to take a look at Authenticated Encryption
I'm using zaph's example for encryption and decryption from this post
The encryption works well, and with my encryption key and iv, returns an NSData object, containing the following string: "bc6983a8 65d412df 2bafdc40 f569874e", which is my input text encrypted. The content of the returned NSData object:
encrypted text: <bc6983a8 65d412df 2bafdc40 f569874e>
This text is sent to a server (json), and the server returns a response, also encrypted with the same encryption key and iv.
My question is, how can I convert the string text that comes from the server's response(bc6983a8 65d412df 2bafdc40 f569874e, for example) into an NSData object so that i can decrypt it?
I tried the follwing:
let plainData = ("<bc6983a8 65d412df 2bafdc40 f569874e>" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!;
let plainData = ("<bc6983a8 65d412df 2bafdc40 f569874e>" as NSString).dataUsingEncoding(NSUTF8StringEncoding)!;
let base64String = plainData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0));
let dataDec = NSData(base64EncodedString: base64String, options: NSDataBase64DecodingOptions(rawValue: 0))
But when displaying the contents of the NSData object, the output is not the one expected:
data Optional("<3c626336 39383361 38203635 64343132 64662032 62616664 63343020 66353639 38373465 3e>")
Any help is appreciated.
You are converting your NSData to the string in a wrong way. Follow this code to convert NSData to string
//This is your encrypted data
var encryptedData = NSData()
let plainData = encryptedData(data: encryptedData, encoding: NSUTF8StringEncoding)
Hope this will work for you.
UPDATE:
This happens because you are not correctly fetching the string from your backend. Use proper method for decoding json data instead of just printing it. "<bc6983a8 65d412df 2bafdc40 f569874e>" is not the string you actually need. You need to decode your json data
See the sample code
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil
{
print("error=\(error)", terminator: "")
return
}
do{ if let newdata = try? (NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.AllowFragments) as! NSDictionary)
{
print(newdata)
}
Here 'newdata' may include the encrypted string you need. Parse it from that json, convert it to NSData and then decrypt.
UPDATE 2
Use this code to convert your data to string
let resstr = NSString(data: YourData, encoding: NSUTF8StringEncoding)