How to get a unique hash or id from a URL in Cocoa? - ios

In my application, I am reading RSS feeds and saving them to a Core Data db using the URL of each specific article as the key. Passing these URLs around the system can be problematic because they can be lengthy, and I'd like a way to generate a unique identifier to store in the db and just pass that around.
I'd also like it to be reconstructable using the same string so that if I get a duplicate URL, I can generate the identifier from it and simply check Core Data for the identifier.
Is there an easy way to do this?

When most people are talking about hashes, they are generally thinking about one-way hashes like SHA1, SHA2, or MD5. While these are imminently useful, they will not allow you to take a hash and reverse it into its original form. They will, however, allow you to do things like compare a user entered password with one they've entered before without ever having to store the actual password -- only the hash.
What you seem to want is string compression or deflation. Luckily, gzip is supported out of the box using the ASIHTTPRequest class. Here's some code for using gzip found in this discussion.
NSString *encodedGzippedString = #"GgAAAB+LCAAAAAAABADtvQdgHEmWJSYvbcp7f0r1StfgdKEIgGATJNiQQBDswYjN5pLsHWlHIymrKoHKZVZlXWYWQMztnbz33nvvvffee++997o7nU4n99//P1xmZAFs9s5K2smeIYCqyB8/fnwfPyK+uE6X2SJPiyZ93eaX+TI9Lcuiatvx/wOwYc0HGgAAAA==";
NSData *decodedGzippedData = [NSData dataFromBase64String:encodedGzippedString];
NSData* unGzippedJsonData = [ASIHTTPRequest uncompressZippedData:decodedGzippedData];
NSString* unGzippedJsonString = [[NSString alloc] initWithData:unGzippedJsonData encoding:NSASCIIStringEncoding];
NSLog(#"Result: %#", unGzippedJsonString);
There is a very good article that discusses hashing using MD5 here:
http://cocoawithlove.com/2009/07/hashvalue-object-for-holding-md5-and.html
Using the CommonCrypto library, there are a number of hash algorithms already built in. You can use the MD5 hasing algorithm like this:
#import <CommonCrypto/CommonDigest.h>
char input[] = "Some data value.";
char result[16];
CC_MD5(input, strlen(input), result);
This will print out the hash in human-readable hex form:
printf("MD5 (\"%s\") = %02x%02x%02x%02x%02x%02x
%02x%02x%02x%02x%02x%02x
%02x%02x%02x%02x\n",
input,
result[0], result[1], result[2], result[3],
result[4], result[5], result[6], result[7],
result[8], result[9], result[10], result[11],
result[12], result[13], result[14], result[15]);
If you would like more information on forward-only hashing, I posted some info as well as production-ready code in this SO answer.

Use SHA1 (apple implementation of it on iOS), it will meet all your requirements (re-running it with the same input generates the same output, changing a single character in the input drastically changes the output).

Using a security hashers like MD5 SHA1 or SHA256 leads to a source code which has to change a hasher function each time the algorithm will become obsolete or week. Then corporations which uses automated audit tools will reject the source code with those functions.
So if you need a hasher function for just removing special characters from urls it's better to have a custom hasher than one of those security hashers.

Related

Different AES encryptors give me different results... why?

I have tried using three different libraries to AES-encrypt a string.
When I use the tool found here I get the following results:
Input: "Test"
key: "MyEncryptionKey1MyEncryptionKey1" (256 Bit)
ECB mode.
this gives me the output Cidor8Ph7pZqPw0x2AwIKw==
But when i'm using the libraries in Swift I get different results.
Using RNCryptor
When i'm using RNcryptor i'm using the following code:
class func encryptMessage(message: String) throws -> String {
guard let messageData = message.data(using: .utf8) else { return message }
let cipherData = RNCryptor.encrypt(data: messageData, withPassword: key)
return cipherData.base64EncodedString()
}
output:
AwF8a+HziYkO4iHdcI3jY8p9QAY461DVgkjkYUFMkuh4A2a8FCfa4RgS9Z37QhJGxIL0Q20RE3BL4nmLQVFOfZmBpj8l0wj9YZgqZmrkxRFYQQ==
Using AESCrypt
When i'm using RNcryptor i'm using the following code:
class func encryptMessageAES(message: String) -> String{
guard let encryptedData = AESCrypt.encrypt(message, password: key) else { return message }
return encryptedData
}
Output:
T5/mR8UT/EXeUobPTLhcFA==
Also if i'm using CryptoSwift i'm getting a third result. My co-worker who does Android always gets the same result - matching the web tool.
I am totally new to encryption and I see that i'm doing something wrong. But I can't really realize what. I should also mention that this encryption is only used to not have chat messages in raw strings showing in Firebase, for those who have access to the database.
The definition of AES is quite precise and when things don't work between different implementations it's often due various things build on top of AES. The AES algorithm itself always operates on binary data. The data you encrypt needs to be binary. The key you use to encrypt with, needs to be binary and If an IV is in play, it also needs to be binary.
In all implementations where you provide data to the implementation that are not binary, a choice have been made on how that data is transformed into a format that can be used with AES. Sometimes these transformations are just simple data conversions like hex or base64 decoding, but other times whole new concepts are in play, like deriving encryption keys from passwords.
All of your three examples uses text as input for the Key, and each implementation have made some choice on how to support that.
The first page you link to has chosen to just interpret an ASCII string as a binary key. This is a terrible choice as it (in addition to being incompatible with everything else) effectively eliminates 1-2 bits per bytes of the key, reducing the strength considerable.
In the RNCryptor example you specify the key with withPassword: key. Here the RNCryptor team have chosen to use a PBKDF2 key deriving function to make an actual AES key. This solves a different usecase, where you have an potential weak password that needs stretching to be secure for encryption. If you have an actual key, this is not the way to go.
In the case of AESCrypt you also seems to be providing a password as input. It's not clear how that would be transformed to an actual key.
There is one more value which you’ll have to set in AES which is iv. So try to find that iv in all three libraries. And also try to set same value for iv. And then you may be able to get same results from all libraries.

How do I encode a NSString to send it to a PHP iOS

I need to send a NSString to a PHP file that goes into a MySQL database.
The problem that I have is with especial characters like "é". When I get the string (from the Facebook SDK for iOS) it comes like this: "Thenáme Thesurnamé", for example.
I send it to a PHP on a server using unicode as charset (I also tried with utf8), but in the database it appears with "é" instead of "é".
The encoding of the database is utf8_unicode_ci
You can always user the ampersand in html to encode such chars.
Try this code:
NSString *resStr = [[NSString alloc] initWithCString:[srcStr cStringUsingEncoding:[NSString defaultCStringEncoding]] encoding:NSMacOSRomanStringEncoding];

QR Code possible data types or standards

I am developing an iOS Application for scanning QR Codes. I am successfully able to scan and get code from QR code.
Question:
My question is what are possible data types and format I can expect from QR Codes?
During my search on google I found QR Code can be used for
Contact data
Calendar data
URL
Email address
Phone number
SMS
Plain text
Geo location
Is this the complete list and is there same standard to represent above data in QR Codes? Means same way of generating QR Code for above QR types.
Is there any standard way of generating and representing data in QR Code?
Basically your text information has to be identifiable for what it is:
There is a very good summary here.
Contact data - use MeCard, or vCard (much more verbose), e.g.: MECARD:Surname, First;ADR:123 Some St., Town, Zip Code, Country;EMAIL:some_name#some_ip.com;TEL:+11800123123;BDAY:19550231;;
Gives:
Calendar data - There are two formats about iCalendar (.ics) & vCalendar (.vcs). These formats can also include location, alarm, to-do items, etc. Note that these are both verbose formats and you may be better off using a short URL to an online file in the file format but the person scanning needs to have internet connectivity and be willing to trust the QR code not to be doing anything bad.
URL: Start your url with the standard format specifier such as http://, e.g.: http://stackoverflow.com/questions/19900835/qr-code-possible-data-types-or-standards
Gives:
Email address - Start with mailto:SomeOne#SomeWhere.org gives:
Phone number - Start with tel: e.g. tel:+1-212-555-1212 gives:
SMS - See the RFC 5724.
Plain text - Just include the text.
Geo location - Use the geo:lat,long,alt format URI: geo:40.71872,-73.98905,100 (100 feet above Googles offices) gives:
WIFI - (ssid is 'abc' and password is '1234'). For WEP encryption: WIFI:S:abc;T:WEP;P:1234;;. For WPA/WPA2: WIFI:S:abc;T:WPA;P:1234;;. Without encryption: WIFI:S:abc;T:nopass;P:1234;;.
All the above example were generated with the Python qrcode package from the command line.
Basically, QR Code returns text data that can be of any type. You can put any type of data in any string format in QR Code. It totally depends on you.
You can consider it as
[NSString stringWithFormat].
Github - Zxing (Barcode Contents) has a summary.
There may or may not be a standard.
If you are looking for non-standard formats,
please update your documentation and contribute to open source.

Convert email attachment to base64

I want to take an attachment from an email and convert it to a base64 string so that I can store it as JSON.
In C#, I would get the attachment as a System.IO.Stream, read it into a byte array, and then use Convert.ToBase64String.
In F# though, I'm not sure how to this (I'm a beginner) and it feels like there is probably a much more functional way of doing things...?
F# combines functional style with object-oriented style, so that you can easily call .NET libraries from F#. Sometimes there are F#-specific libraries that give you a more functional style for some tasks (like list processing), but I don't think there is anything like that for base64 encoding and streams.
So, given a stream, you can read it into a buffer and then convert to base64 using .NET types as follows:
open System
open System.IO
let stream = // Some stream, for example: new MemoryStream([| 1uy; 2uy; 3uy; 4uy |])
let buffer = Array.zeroCreate (int stream.Length)
stream.Read(buffer, 0, buffer.Length)
Convert.ToBase64String(buffer)

Twitter API cursor based pagination (JSON issue) PHP

as you know Twitter has posted a new cursor based pagination for some API methods.
Currently, I'm facing a problem when encoding the json object because the cursor itself is actually a 64-bit numbers and not supported for json encoding in PHP.
next_cursor 1299072354878293926
Any solution for this? I can't believe why didn't Twitter just return string for it...hmmp
thx
PHP 5.2+ should convert 64-bit numbers to floats, which is better than previous versions of PHP (which would just convert it to the maximum 32-bit value). Best bet is to move to a 64-bit version of PHP, but updating to PHP 5.2+ will at least get you up and running.
If you are stuck with 32 bit system, you could convert the cursor to string using regex and then use it for further requests.
Here's PHP function that I am using to achieve this:
function jsonIntToStr($json){
$pattern = "/\"next_cursor\":([0-9]+),/";
$replace = "\"next_cursor\":\"$1\",";
$new_json = preg_replace($pattern, $replace, $json);
$pattern = "/\"previous_cursor\":([0-9]+),/";
$replace = "\"previous_cursor\":\"$1\",";
$new_json = preg_replace($pattern, $replace, $new_json);
return $new_json;
}
and you could use it like:
$json_result = json_decode(jsonIntToStr($twitter_response));
Got it from twitter development talk google group.
Since PHP 5.4.0 (currently in beta), it is possible to use the fourth parameter of json_encode and set it to JSON_BIGINT_AS_STRING.

Resources